File indexing completed on 2024-03-24 17:07:17

0001 /*
0002 *  Copyright 2019 Michail Vourlakos <mvourlakos@gmail.com>
0003 *
0004 *  This file is part of Latte-Dock
0005 *
0006 *  Latte-Dock is free software; you can redistribute it and/or
0007 *  modify it under the terms of the GNU General Public License as
0008 *  published by the Free Software Foundation; either version 2 of
0009 *  the License, or (at your option) any later version.
0010 *
0011 *  Latte-Dock is distributed in the hope that it will be useful,
0012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 *  GNU General Public License for more details.
0015 *
0016 *  You should have received a copy of the GNU General Public License
0017 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018 */
0019 
0020 #include "shareddelegate.h"
0021 
0022 // local
0023 #include "persistentmenu.h"
0024 #include "../settingsdialog.h"
0025 #include "../tools/settingstools.h"
0026 
0027 // Qt
0028 #include <QAction>
0029 #include <QApplication>
0030 #include <QComboBox>
0031 #include <QDebug>
0032 #include <QMenu>
0033 #include <QWidget>
0034 #include <QModelIndex>
0035 #include <QPainter>
0036 #include <QPushButton>
0037 #include <QString>
0038 #include <QTextDocument>
0039 
0040 
0041 SharedDelegate::SharedDelegate(QObject *parent)
0042     : QItemDelegate(parent)
0043 {
0044     auto *settingsDialog = qobject_cast<Latte::SettingsDialog *>(parent);
0045 
0046     if (settingsDialog) {
0047         m_settingsDialog = settingsDialog;
0048     }
0049 }
0050 
0051 QWidget *SharedDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
0052 {
0053     QStringList assignedShares = index.model()->data(index, Qt::UserRole).toStringList();
0054     QStringList availableShares = m_settingsDialog->availableSharesFor(index.row());
0055 
0056     QPushButton *button = new QPushButton(parent);
0057     PersistentMenu *menu = new PersistentMenu(button);
0058     button->setMenu(menu);
0059 
0060     menu->setMinimumWidth(option.rect.width());
0061 
0062     for (unsigned int i = 0; i < availableShares.count(); ++i) {
0063         QString layoutName = m_settingsDialog->nameForId(availableShares[i]);
0064         QAction *action = new QAction(layoutName);
0065         action->setData(availableShares[i]);
0066         action->setCheckable(true);
0067         action->setChecked(assignedShares.contains(availableShares[i]));
0068 
0069         if (m_settingsDialog->isActive(layoutName)) {
0070             QFont font = action->font();
0071             font.setBold(true);
0072             action->setFont(font);
0073         }
0074 
0075         menu->addAction(action);
0076 
0077         connect(action, &QAction::toggled, this, [this, button, action]() {
0078             updateButtonText(button);
0079 
0080             if (action->isChecked()) {
0081                 m_settingsDialog->addShareInCurrent(action->data().toString());
0082             } else {
0083                 m_settingsDialog->removeShareFromCurrent(action->data().toString());
0084             }
0085         });
0086     }
0087 
0088     updateButtonText(button);
0089 
0090     return button;
0091 }
0092 
0093 void SharedDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
0094 {
0095     updateButtonText(editor);
0096 }
0097 
0098 void SharedDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
0099 {
0100     QPushButton *button = static_cast<QPushButton *>(editor);
0101 
0102     QStringList assignedLayouts;
0103     foreach (QAction *action, button->menu()->actions()) {
0104         if (action->isChecked()) {
0105             assignedLayouts << action->data().toString();
0106         }
0107     }
0108 
0109     model->setData(index, assignedLayouts, Qt::UserRole);
0110 }
0111 
0112 void SharedDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
0113 {
0114     editor->setGeometry(option.rect);
0115 }
0116 
0117 void SharedDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
0118 {
0119     QStyleOptionViewItem myOptions = option;
0120     //! Remove the focus dotted lines
0121     myOptions.state = (myOptions.state & ~QStyle::State_HasFocus);
0122     painter->save();
0123 
0124     QStringList assignedLayoutsIds = index.model()->data(index, Qt::UserRole).toStringList();
0125     QStringList assignedLayouts;
0126 
0127     for (const auto &id : assignedLayoutsIds) {
0128         assignedLayouts << m_settingsDialog->nameForId(id);
0129     }
0130 
0131     if (assignedLayouts.count() > 0) {
0132         myOptions.text = joined(assignedLayouts, true);
0133 
0134         QTextDocument doc;
0135         QString css;
0136         QString sharesText = myOptions.text;
0137 
0138         QPalette::ColorRole applyColor = Latte::isSelected(option) ? QPalette::HighlightedText : QPalette::Text;
0139         QBrush nBrush = option.palette.brush(Latte::colorGroup(option), applyColor);
0140 
0141         css = QString("body { color : %1; }").arg(nBrush.color().name());
0142 
0143         doc.setDefaultStyleSheet(css);
0144         doc.setHtml("<body>" + myOptions.text + "</body>");
0145 
0146         myOptions.text = "";
0147         myOptions.widget->style()->drawControl(QStyle::CE_ItemViewItem, &myOptions, painter);
0148 
0149         //we need an offset to be in the same vertical center of TextEdit
0150         int offsetY = ((myOptions.rect.height() - doc.size().height()) / 2);
0151 
0152         if ((qApp->layoutDirection() == Qt::RightToLeft) && !sharesText.isEmpty()) {
0153             int textWidth = doc.size().width();
0154 
0155             painter->translate(qMax(myOptions.rect.left(), myOptions.rect.right() - textWidth), myOptions.rect.top() + offsetY + 1);
0156         } else {
0157             painter->translate(myOptions.rect.left(), myOptions.rect.top() + offsetY + 1);
0158         }
0159 
0160         QRect clip(0, 0, myOptions.rect.width(), myOptions.rect.height());
0161         doc.drawContents(painter, clip);
0162     } else {
0163         QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &myOptions, painter);
0164     }
0165 
0166     painter->restore();
0167 }
0168 
0169 void SharedDelegate::updateButtonText(QWidget *editor) const
0170 {
0171     if (!editor) {
0172         return;
0173     }
0174     QPushButton *button = static_cast<QPushButton *>(editor);
0175     QStringList assignedLayouts;
0176 
0177     foreach (QAction *action, button->menu()->actions()) {
0178         if (action->isChecked()) {
0179             assignedLayouts << m_settingsDialog->nameForId(action->data().toString());
0180         }
0181     }
0182 
0183     button->setText(joined(assignedLayouts));
0184 }
0185 
0186 QString SharedDelegate::joined(const QStringList &layouts, bool boldForActive) const
0187 {
0188     QString finalText;
0189 
0190     int i = 0;
0191 
0192     for (const auto &layoutName : layouts) {
0193         if (i > 0) {
0194             finalText += ", ";
0195         }
0196         i++;
0197 
0198         bool isActive{false};
0199 
0200         if (boldForActive && m_settingsDialog->isActive(layoutName)) {
0201             isActive = true;
0202         }
0203 
0204         finalText += isActive ? "<b>" + layoutName + "</b>" : layoutName;
0205     }
0206 
0207     return finalText;
0208 }