File indexing completed on 2024-04-21 03:56:14

0001 /*
0002     SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "scriptablereparentingwidget.h"
0008 
0009 #include <QJSEngine>
0010 #include <QPlainTextEdit>
0011 #include <QTreeView>
0012 #include <QVBoxLayout>
0013 
0014 #include <QComboBox>
0015 #include <QLabel>
0016 #include <QSplitter>
0017 
0018 static const char *const threadingFunctionNames[] = {"None", "Flat List", "Straight Line Tree", "Dragon Teeth 1", "Dragon Teeth 2", "Specified parents 1"};
0019 
0020 static const char *const threadingFunctionBodies[] = {"",
0021                                                       "return false;",
0022                                                       "return true;",
0023                                                       "if (descendant % 3 ==1)\n"
0024                                                       "    return false;\n"
0025                                                       "return true;",
0026                                                       "if (descendant % 4 ==1)\n"
0027                                                       "    return false;\n"
0028                                                       "return true;",
0029                                                       "var threaddata = [[1, 2, 3, 4],\n"
0030                                                       "                  [13, 14, 15],\n"
0031                                                       "                  [13, 16, 17],\n"
0032                                                       "                  [5, 6]];\n"
0033                                                       "\n"
0034                                                       "for (var i = 0; i < threaddata.length; ++i)\n"
0035                                                       "{\n"
0036                                                       "  var a = threaddata[i].indexOf(ancestor);\n"
0037                                                       "  var d = threaddata[i].indexOf(descendant);\n"
0038                                                       "  if (a >= 0 && d >= 0)\n"
0039                                                       "    return a < d;\n"
0040                                                       "}\n"
0041                                                       "return false;"};
0042 
0043 ScriptableReparentingProxyModel::ScriptableReparentingProxyModel(QObject *parent)
0044     : KReparentingProxyModel(parent)
0045     , m_scriptEngine(new QJSEngine(this))
0046 {
0047 }
0048 
0049 bool ScriptableReparentingProxyModel::isDescendantOf(const QModelIndex &ancestor, const QModelIndex &descendant) const
0050 {
0051     if (!m_implementationFunction.isCallable()) {
0052         return KReparentingProxyModel::isDescendantOf(ancestor, descendant);
0053     }
0054 
0055     QJSValue returnValue = m_implementationFunction.call({ancestor.data().toInt(), descendant.data().toInt()});
0056 
0057     if (!returnValue.isBool()) {
0058         return KReparentingProxyModel::isDescendantOf(ancestor, descendant);
0059     }
0060 
0061     return returnValue.toBool();
0062 }
0063 
0064 void ScriptableReparentingProxyModel::setImplementation(const QString &implementation)
0065 {
0066     beginChangeRule();
0067     m_implementationFunction = m_scriptEngine->evaluate(implementation);
0068     m_implementationFunction = m_scriptEngine->globalObject().property(QStringLiteral("isDescendantOf"));
0069     endChangeRule();
0070 }
0071 
0072 ScriptableReparentingWidget::ScriptableReparentingWidget(QAbstractItemModel *rootModel, QWidget *parent, Qt::WindowFlags f)
0073     : QWidget(parent, f)
0074     , m_reparentingProxyModel(new ScriptableReparentingProxyModel(this))
0075 {
0076     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0077     QSplitter *splitter = new QSplitter(Qt::Vertical, this);
0078     mainLayout->addWidget(splitter);
0079 
0080     m_treeView = new QTreeView(splitter);
0081     QWidget *container = new QWidget(splitter);
0082     QVBoxLayout *layout = new QVBoxLayout(container);
0083     m_textEdit = new QPlainTextEdit(container);
0084     m_textEdit->setFont(QFont(QStringLiteral("monospace")));
0085 
0086     m_comboBox = new QComboBox(container);
0087     for (int i = 0; i < int(sizeof threadingFunctionNames / sizeof *threadingFunctionNames); ++i) {
0088         m_comboBox->addItem(*(threadingFunctionNames + i), *(threadingFunctionBodies + i));
0089     }
0090     layout->addWidget(m_comboBox);
0091     connect(m_comboBox, SIGNAL(currentIndexChanged(int)), SLOT(setExampleFunction(int)));
0092 
0093     layout->addWidget(new QLabel(QStringLiteral("function isDescendantOf (ancestor, descendant) {"), container));
0094     QHBoxLayout *indentedLayout = new QHBoxLayout;
0095     indentedLayout->addSpacing(30);
0096     indentedLayout->addWidget(m_textEdit);
0097     layout->addLayout(indentedLayout);
0098     layout->addWidget(new QLabel(QStringLiteral("}"), container));
0099 
0100     m_reparentingProxyModel->setSourceModel(rootModel);
0101     m_treeView->setModel(m_reparentingProxyModel);
0102 
0103     splitter->setStretchFactor(0, 100);
0104 
0105     connect(m_textEdit, SIGNAL(textChanged()), SLOT(textChanged()));
0106     textChanged();
0107 }
0108 
0109 void ScriptableReparentingWidget::setExampleFunction(int index)
0110 {
0111     m_textEdit->setPlainText(m_comboBox->itemData(index).toString());
0112 }
0113 
0114 void ScriptableReparentingWidget::textChanged()
0115 {
0116     m_reparentingProxyModel->setImplementation("function isDescendantOf (ancestor, descendant) { " + m_textEdit->toPlainText() + " }");
0117     m_treeView->expandAll();
0118 }
0119 
0120 #include "moc_scriptablereparentingwidget.cpp"