File indexing completed on 2024-11-03 09:57:24

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 <QPlainTextEdit>
0010 #include <QScriptEngine>
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 QScriptEngine(this))
0046 {
0047 }
0048 
0049 bool ScriptableReparentingProxyModel::isDescendantOf(const QModelIndex &ancestor, const QModelIndex &descendant) const
0050 {
0051     if (!m_implementationFunction.isValid()) {
0052         return KReparentingProxyModel::isDescendantOf(ancestor, descendant);
0053     }
0054 
0055     QScriptValueList arguments = QScriptValueList() << ancestor.data().toInt() << descendant.data().toInt();
0056     QScriptValue returnValue = m_implementationFunction.call(QScriptValue(), arguments);
0057 
0058     if (!returnValue.isBool()) {
0059         return KReparentingProxyModel::isDescendantOf(ancestor, descendant);
0060     }
0061 
0062     return returnValue.toBool();
0063 }
0064 
0065 void ScriptableReparentingProxyModel::setImplementation(const QString &implementation)
0066 {
0067     beginChangeRule();
0068     m_implementationFunction = m_scriptEngine->evaluate(implementation);
0069     m_implementationFunction = m_scriptEngine->globalObject().property(QStringLiteral("isDescendantOf"));
0070     endChangeRule();
0071 }
0072 
0073 ScriptableReparentingWidget::ScriptableReparentingWidget(QAbstractItemModel *rootModel, QWidget *parent, Qt::WindowFlags f)
0074     : QWidget(parent, f)
0075     , m_reparentingProxyModel(new ScriptableReparentingProxyModel(this))
0076 {
0077     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0078     QSplitter *splitter = new QSplitter(Qt::Vertical, this);
0079     mainLayout->addWidget(splitter);
0080 
0081     m_treeView = new QTreeView(splitter);
0082     QWidget *container = new QWidget(splitter);
0083     QVBoxLayout *layout = new QVBoxLayout(container);
0084     m_textEdit = new QPlainTextEdit(container);
0085     m_textEdit->setFont(QFont(QStringLiteral("monospace")));
0086 
0087     m_comboBox = new QComboBox(container);
0088     for (int i = 0; i < int(sizeof threadingFunctionNames / sizeof *threadingFunctionNames); ++i) {
0089         m_comboBox->addItem(*(threadingFunctionNames + i), *(threadingFunctionBodies + i));
0090     }
0091     layout->addWidget(m_comboBox);
0092     connect(m_comboBox, SIGNAL(currentIndexChanged(int)), SLOT(setExampleFunction(int)));
0093 
0094     layout->addWidget(new QLabel(QStringLiteral("function isDescendantOf (ancestor, descendant) {"), container));
0095     QHBoxLayout *indentedLayout = new QHBoxLayout;
0096     indentedLayout->addSpacing(30);
0097     indentedLayout->addWidget(m_textEdit);
0098     layout->addLayout(indentedLayout);
0099     layout->addWidget(new QLabel(QStringLiteral("}"), container));
0100 
0101     m_reparentingProxyModel->setSourceModel(rootModel);
0102     m_treeView->setModel(m_reparentingProxyModel);
0103 
0104     splitter->setStretchFactor(0, 100);
0105 
0106     connect(m_textEdit, SIGNAL(textChanged()), SLOT(textChanged()));
0107     textChanged();
0108 }
0109 
0110 void ScriptableReparentingWidget::setExampleFunction(int index)
0111 {
0112     m_textEdit->setPlainText(m_comboBox->itemData(index).toString());
0113 }
0114 
0115 void ScriptableReparentingWidget::textChanged()
0116 {
0117     m_reparentingProxyModel->setImplementation("function isDescendantOf (ancestor, descendant) { " + m_textEdit->toPlainText() + " }");
0118     m_treeView->expandAll();
0119 }
0120 
0121 #include "moc_scriptablereparentingwidget.cpp"