File indexing completed on 2024-04-28 05:48:39

0001 //
0002 // Description: Widget for configuring build targets
0003 //
0004 // SPDX-FileCopyrightText: 2011-2022 Kåre Särs <kare.sars@iki.fi>
0005 //
0006 //  SPDX-License-Identifier: LGPL-2.0-only
0007 
0008 #include "targets.h"
0009 #include <KLocalizedString>
0010 #include <QApplication>
0011 #include <QDebug>
0012 #include <QEvent>
0013 #include <QHeaderView>
0014 #include <QIcon>
0015 #include <QKeyEvent>
0016 
0017 TargetsUi::TargetsUi(QObject *view, QWidget *parent)
0018     : QWidget(parent)
0019 {
0020     proxyModel.setSourceModel(&targetsModel);
0021 
0022     targetFilterEdit = new QLineEdit(this);
0023     targetFilterEdit->setPlaceholderText(i18n("Filter targets, use arrow keys to select, Enter to execute"));
0024     targetFilterEdit->setClearButtonEnabled(true);
0025 
0026     newTarget = new QToolButton(this);
0027     newTarget->setToolTip(i18n("Create new set of targets"));
0028     newTarget->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
0029 
0030     copyTarget = new QToolButton(this);
0031     copyTarget->setToolTip(i18n("Copy command or target set"));
0032     copyTarget->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
0033 
0034     deleteTarget = new QToolButton(this);
0035     deleteTarget->setToolTip(i18n("Delete current target or current set of targets"));
0036     deleteTarget->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0037 
0038     addButton = new QToolButton(this);
0039     addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
0040     addButton->setToolTip(i18n("Add new target"));
0041 
0042     buildButton = new QToolButton(this);
0043     buildButton->setIcon(QIcon::fromTheme(QStringLiteral("run-build")));
0044     buildButton->setToolTip(i18n("Build selected target"));
0045 
0046     runButton = new QToolButton(this);
0047     runButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
0048     runButton->setToolTip(i18n("Build and run selected target"));
0049 
0050     moveTargetUp = new QToolButton(this);
0051     moveTargetUp->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
0052     moveTargetUp->setToolTip(i18n("Move selected target up"));
0053 
0054     moveTargetDown = new QToolButton(this);
0055     moveTargetDown->setIcon(QIcon::fromTheme(QStringLiteral("go-down")));
0056     moveTargetDown->setToolTip(i18n("Move selected target down"));
0057 
0058     targetsView = new QTreeView(this);
0059     targetsView->setAlternatingRowColors(true);
0060 
0061     targetsView->setModel(&proxyModel);
0062     m_delegate = new TargetHtmlDelegate(view);
0063     targetsView->setItemDelegate(m_delegate);
0064     targetsView->setSelectionBehavior(QAbstractItemView::SelectItems);
0065     targetsView->setEditTriggers(QAbstractItemView::AnyKeyPressed | QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
0066     targetsView->expandAll();
0067     targetsView->header()->setStretchLastSection(false);
0068     targetsView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
0069     targetsView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
0070     targetsView->header()->setSectionResizeMode(2, QHeaderView::Stretch);
0071     QHBoxLayout *tLayout = new QHBoxLayout();
0072 
0073     tLayout->addWidget(targetFilterEdit);
0074     tLayout->addWidget(buildButton);
0075     tLayout->addWidget(runButton);
0076     tLayout->addSpacing(15);
0077     tLayout->addWidget(addButton);
0078     tLayout->addWidget(newTarget);
0079     tLayout->addWidget(copyTarget);
0080     tLayout->addWidget(moveTargetUp);
0081     tLayout->addWidget(moveTargetDown);
0082     tLayout->addWidget(deleteTarget);
0083     int leftMargin = QApplication::style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
0084     tLayout->setContentsMargins(leftMargin, 0, 0, 0);
0085 
0086     QVBoxLayout *layout = new QVBoxLayout(this);
0087     layout->addLayout(tLayout);
0088     layout->addWidget(targetsView);
0089     layout->setContentsMargins(0, 0, 0, 0);
0090 
0091     connect(targetsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TargetsUi::targetActivated);
0092 
0093     connect(targetsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TargetsUi::updateTargetsButtonStates);
0094     connect(&targetsModel, &QAbstractItemModel::dataChanged, this, &TargetsUi::updateTargetsButtonStates);
0095     connect(&targetsModel, &QAbstractItemModel::rowsMoved, this, &TargetsUi::updateTargetsButtonStates);
0096 
0097     connect(targetFilterEdit, &QLineEdit::textChanged, this, [this](const QString &text) {
0098         proxyModel.setFilter(text);
0099         targetsView->expandAll();
0100         targetsView->scrollTo(targetsView->currentIndex());
0101     });
0102 
0103     targetsView->installEventFilter(this);
0104     targetFilterEdit->installEventFilter(this);
0105 }
0106 
0107 void TargetsUi::targetActivated(const QModelIndex &index)
0108 {
0109     // qDebug() << index;
0110     if (!index.isValid()) {
0111         return;
0112     }
0113     QModelIndex rootItem = index;
0114     if (rootItem.parent().isValid()) {
0115         rootItem = rootItem.parent();
0116     }
0117 }
0118 
0119 void TargetsUi::updateTargetsButtonStates()
0120 {
0121     QModelIndex currentIndex = targetsView->currentIndex();
0122     if (!currentIndex.isValid()) {
0123         buildButton->setEnabled(false);
0124         runButton->setEnabled(false);
0125         moveTargetUp->setEnabled(false);
0126         moveTargetDown->setEnabled(false);
0127         return;
0128     }
0129 
0130     moveTargetUp->setEnabled(currentIndex.row() > 0);
0131 
0132     // If this is a root item
0133     if (!currentIndex.parent().isValid()) {
0134         // move down button
0135         int rows = targetsView->model()->rowCount();
0136         moveTargetDown->setEnabled(currentIndex.row() < rows - 1);
0137 
0138         // try it's first child to see if we can build/run
0139         currentIndex = targetsView->model()->index(0, 0, currentIndex.siblingAtColumn(0));
0140         if (!currentIndex.isValid()) {
0141             buildButton->setEnabled(false);
0142             runButton->setEnabled(false);
0143             return;
0144         }
0145     } else {
0146         int rows = targetsView->model()->rowCount(currentIndex.parent());
0147         moveTargetDown->setEnabled(currentIndex.row() < rows - 1);
0148     }
0149 
0150     const bool hasBuildCmd = !currentIndex.siblingAtColumn(1).data().toString().isEmpty();
0151     const bool hasRunCmd = !currentIndex.siblingAtColumn(2).data().toString().isEmpty();
0152     buildButton->setEnabled(hasBuildCmd);
0153     // Run button can be enabled even if there is no build command
0154     runButton->setEnabled(hasRunCmd);
0155 }
0156 
0157 bool TargetsUi::eventFilter(QObject *obj, QEvent *event)
0158 {
0159     if (event->type() == QEvent::KeyPress) {
0160         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
0161         if (obj == targetsView) {
0162             if (((keyEvent->key() == Qt::Key_Return) || (keyEvent->key() == Qt::Key_Enter)) && m_delegate && !m_delegate->isEditing()) {
0163                 Q_EMIT enterPressed();
0164                 return true;
0165             }
0166         }
0167         if (obj == targetFilterEdit) {
0168             switch (keyEvent->key()) {
0169             case Qt::Key_Up:
0170             case Qt::Key_Down:
0171             case Qt::Key_PageUp:
0172             case Qt::Key_PageDown:
0173             case Qt::Key_Return:
0174             case Qt::Key_Enter:
0175                 QCoreApplication::sendEvent(targetsView, event);
0176                 return true;
0177             case Qt::Key_Left:
0178             case Qt::Key_Right:
0179             case Qt::Key_F2:
0180                 // NOTE: I failed to find a generic "platform edit key" shortcut, but it seems
0181                 // Key_F2 is hard-coded on non-OSX and Return/Enter on OSX in:
0182                 // void QAbstractItemView::keyPressEvent(QKeyEvent *event)
0183                 if (targetFilterEdit->text().isEmpty()) {
0184                     QCoreApplication::sendEvent(targetsView, event);
0185                     return true;
0186                 }
0187                 break;
0188             }
0189         }
0190     }
0191     return QWidget::eventFilter(obj, event);
0192 }
0193 
0194 #include "moc_targets.cpp"