File indexing completed on 2024-04-14 03:53:50
0001 /* 0002 SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "dynamictreewidget.h" 0008 0009 #include <QComboBox> 0010 #include <QDebug> 0011 #include <QHBoxLayout> 0012 #include <QPlainTextEdit> 0013 #include <QPushButton> 0014 #include <QRadioButton> 0015 #include <QTabWidget> 0016 #include <QTreeView> 0017 0018 #include "dynamictreemodel.h" 0019 0020 static const char *const treePredefinesNames[] = {"Flat List", "Straight Line Tree", "Dragon Teeth 1", "Dragon Teeth 2", "Random Tree 1"}; 0021 0022 static const char *const treePredefinesContent[] = { 0023 " - 1" 0024 " - 1" 0025 " - 1" 0026 " - 1" 0027 " - 1" 0028 " - 1" 0029 " - 1" 0030 " - 1" 0031 " - 1" 0032 " - 1" 0033 " - 1" 0034 " - 1" 0035 " - 1" 0036 " - 1" 0037 " - 1" 0038 " - 1", 0039 0040 " - 1" 0041 " - - 1" 0042 " - - - 1" 0043 " - - - - 1" 0044 " - - - - - 1" 0045 " - - - - - - 1" 0046 " - - - - - - - 1" 0047 " - - - - - - - - 1" 0048 " - - - - - - - - - 1" 0049 " - - - - - - - - - - 1" 0050 " - - - - - - - - - - - 1" 0051 " - - - - - - - - - - - - 1" 0052 " - - - - - - - - - - - - - 1" 0053 " - - - - - - - - - - - - - - 1" 0054 " - - - - - - - - - - - - - - - 1" 0055 " - - - - - - - - - - - - - - - - 1", 0056 0057 " - 1" 0058 " - - 1" 0059 " - - - 1" 0060 " - - - - 1" 0061 " - 1" 0062 " - - 1" 0063 " - - - 1" 0064 " - - - - 1" 0065 " - 1" 0066 " - - 1" 0067 " - - - 1" 0068 " - - - - 1" 0069 " - 1" 0070 " - - 1" 0071 " - - - 1" 0072 " - - - - 1", 0073 0074 " - 1" 0075 " - - 1" 0076 " - - - 1" 0077 " - - - - 1" 0078 " - - - - - 1" 0079 " - 1" 0080 " - - 1" 0081 " - - - 1" 0082 " - - - - 1" 0083 " - - - - - 1" 0084 " - 1" 0085 " - - 1" 0086 " - - - 1" 0087 " - - - - 1" 0088 " - - - - - 1" 0089 " - 1" 0090 " - - 1" 0091 " - - - 1" 0092 " - - - - 1" 0093 " - - - - - 1", 0094 0095 " - 1" 0096 " - 2" 0097 " - - 3" 0098 " - - - 4" 0099 " - 5" 0100 " - 6" 0101 " - 7" 0102 " - - 8" 0103 " - - - 9" 0104 " - - - 10" 0105 " - - - - 11" 0106 " - - - 12" 0107 " - - - - 13" 0108 " - 14" 0109 " - 15"}; 0110 0111 static const char *const insertSubTreePredefinesNames[] = {"Flat List", "Straight Line Tree", "Dragon Teeth 1", "Dragon Teeth 2", "Random Tree 1"}; 0112 0113 static const char *const insertSubTreePredefinesContent[] = { 0114 " - 1\n" 0115 " - 1\n" 0116 " - 1\n" 0117 " - 1\n", 0118 0119 " - 1\n" 0120 " - - 1\n" 0121 " - - - 1\n" 0122 " - - - - 1\n", 0123 0124 " - 1\n" 0125 " - - 1\n" 0126 " - 1\n" 0127 " - - 1\n", 0128 0129 " - 1\n" 0130 " - - 1\n" 0131 " - - - 1\n" 0132 " - 1\n" 0133 " - - 1\n" 0134 " - - - 1\n", 0135 0136 " - 1\n" 0137 " - 2\n" 0138 " - - 3\n" 0139 " - - - 4\n" 0140 " - 5\n"}; 0141 0142 DynamicTreeWidget::DynamicTreeWidget(DynamicTreeModel *rootModel, QWidget *parent, Qt::WindowFlags f) 0143 : QWidget(parent, f) 0144 , m_dynamicTreeModel(rootModel) 0145 { 0146 QTabWidget *tabWidget = new QTabWidget(this); 0147 0148 QHBoxLayout *layout = new QHBoxLayout(this); 0149 layout->addWidget(tabWidget); 0150 0151 QWidget *editContainer = new QWidget(tabWidget); 0152 QVBoxLayout *editLayout = new QVBoxLayout(editContainer); 0153 0154 m_treePredefines = new QComboBox(editContainer); 0155 for (uint i = 0; i < sizeof treePredefinesNames / sizeof *treePredefinesNames; ++i) { 0156 m_treePredefines->addItem(*(treePredefinesNames + i), *(treePredefinesContent + i)); 0157 } 0158 editLayout->addWidget(m_treePredefines); 0159 connect(m_treePredefines, &QComboBox::currentIndexChanged, this, &DynamicTreeWidget::setTreePredefine); 0160 0161 m_textEdit = new QPlainTextEdit(editContainer); 0162 editLayout->addWidget(m_textEdit); 0163 0164 QWidget *viewContainer = new QWidget(tabWidget); 0165 0166 QVBoxLayout *viewLayout = new QVBoxLayout(viewContainer); 0167 0168 m_treeView = new QTreeView(tabWidget); 0169 m_treeView->setModel(rootModel); 0170 m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); 0171 m_treeView->setDragDropMode(QAbstractItemView::InternalMove); 0172 m_treeView->setDragEnabled(true); 0173 m_treeView->setAcceptDrops(true); 0174 m_treeView->setDropIndicatorShown(true); 0175 0176 QPushButton *m_removeButton = new QPushButton(QStringLiteral("Remove"), tabWidget); 0177 0178 connect(m_removeButton, &QAbstractButton::clicked, this, &DynamicTreeWidget::removeSelected); 0179 0180 m_insertSubTreePredefines = new QComboBox(this); 0181 for (uint i = 0; i < sizeof insertSubTreePredefinesNames / sizeof *insertSubTreePredefinesNames; ++i) { 0182 m_insertSubTreePredefines->addItem(*(insertSubTreePredefinesNames + i), *(insertSubTreePredefinesContent + i)); 0183 } 0184 editLayout->addWidget(m_insertSubTreePredefines); 0185 connect(m_insertSubTreePredefines, &QComboBox::currentIndexChanged, this, &DynamicTreeWidget::setInsertSubTreePredefine); 0186 0187 m_insertPatternTextEdit = new QPlainTextEdit(tabWidget); 0188 m_insertPatternTextEdit->setMaximumHeight(100); 0189 0190 m_insertChildren = new QRadioButton(QStringLiteral("Insert Children"), tabWidget); 0191 m_insertSiblingsAbove = new QRadioButton(QStringLiteral("Insert Siblings Above"), tabWidget); 0192 m_insertSiblingsBelow = new QRadioButton(QStringLiteral("Insert Siblings Below"), tabWidget); 0193 0194 m_insertChildren->setChecked(true); 0195 0196 QPushButton *m_insertButton = new QPushButton(QStringLiteral("Insert"), tabWidget); 0197 0198 connect(m_insertButton, &QAbstractButton::clicked, this, &DynamicTreeWidget::insertSelected); 0199 0200 QPushButton *m_resetButton = new QPushButton(QStringLiteral("Reset"), tabWidget); 0201 0202 connect(m_resetButton, &QAbstractButton::clicked, this, &DynamicTreeWidget::resetModel); 0203 0204 viewLayout->addWidget(m_treeView); 0205 0206 viewLayout->addWidget(m_removeButton); 0207 0208 viewLayout->addWidget(m_insertSubTreePredefines); 0209 viewLayout->addWidget(m_insertPatternTextEdit); 0210 viewLayout->addWidget(m_insertChildren); 0211 viewLayout->addWidget(m_insertSiblingsAbove); 0212 viewLayout->addWidget(m_insertSiblingsBelow); 0213 viewLayout->addWidget(m_insertButton); 0214 viewLayout->addWidget(m_resetButton); 0215 0216 tabWidget->addTab(editContainer, QStringLiteral("Edit")); 0217 tabWidget->addTab(viewContainer, QStringLiteral("View")); 0218 0219 tabWidget->setCurrentIndex(ViewTab); 0220 0221 connect(tabWidget, &QTabWidget::currentChanged, this, &DynamicTreeWidget::currentChanged); 0222 stringToModel( 0223 QLatin1String(" - 1" 0224 " - 2" 0225 " - - 3" 0226 " - - 4" 0227 " - - 5" 0228 " - 6" 0229 " - 7" 0230 " - - 8" 0231 " - - - 9" 0232 " - - - 10" 0233 " - - 11" 0234 " - - 12" 0235 " - 13" 0236 " - 14" 0237 " - 15" 0238 " - - 16" 0239 " - - - 17" 0240 " - - - 18" 0241 " - 19" 0242 " - 20" 0243 " - 21")); 0244 } 0245 0246 void DynamicTreeWidget::setInitialTree(const QString &treeString) 0247 { 0248 stringToModel(treeString); 0249 } 0250 0251 void DynamicTreeWidget::currentChanged(int index) 0252 { 0253 switch (index) { 0254 case EditTab: 0255 m_textEdit->setPlainText(modelTreeToString(0, QModelIndex())); 0256 break; 0257 case ViewTab: 0258 if (m_textEdit->document()->isModified()) { 0259 stringToModel(m_textEdit->toPlainText()); 0260 } 0261 m_textEdit->document()->setModified(false); 0262 break; 0263 } 0264 } 0265 0266 void DynamicTreeWidget::stringToModel(const QString &treeString) 0267 { 0268 if (treeString.isEmpty()) { 0269 return; 0270 } 0271 0272 m_dynamicTreeModel->clear(); 0273 ModelInsertCommand *command = new ModelInsertCommand(m_dynamicTreeModel, this); 0274 command->setStartRow(0); 0275 command->interpret(treeString); 0276 command->doCommand(); 0277 m_treeView->expandAll(); 0278 } 0279 0280 QString DynamicTreeWidget::modelTreeToString(int depth, const QModelIndex &parent) 0281 { 0282 QString result; 0283 QModelIndex idx; 0284 static const int column = 0; 0285 QString prefix; 0286 0287 for (int i = 0; i <= depth; ++i) { 0288 prefix.append(" -"); 0289 } 0290 0291 for (int row = 0; row < m_dynamicTreeModel->rowCount(parent); ++row) { 0292 idx = m_dynamicTreeModel->index(row, column, parent); 0293 result.append(prefix + " " + idx.data().toString() + "\n"); 0294 if (m_dynamicTreeModel->hasChildren(idx)) { 0295 result.append(modelTreeToString(depth + 1, idx)); 0296 } 0297 } 0298 return result; 0299 } 0300 0301 void DynamicTreeWidget::removeSelected() 0302 { 0303 QModelIndex parent; 0304 ModelRemoveCommand *removeCommand = new ModelRemoveCommand(m_dynamicTreeModel, this); 0305 QItemSelection selection = m_treeView->selectionModel()->selection(); 0306 while (!selection.isEmpty()) { 0307 const QItemSelectionRange range = selection.takeFirst(); // The selection model will take care of updating persistent indexes. 0308 Q_ASSERT(range.isValid()); 0309 qDebug() << range.parent() << range.top() << range.bottom(); 0310 removeCommand->setAncestorRowNumbers(m_dynamicTreeModel->indexToPath(range.parent())); 0311 removeCommand->setStartRow(range.top()); 0312 removeCommand->setEndRow(range.bottom()); 0313 0314 qDebug() << m_dynamicTreeModel->indexToPath(range.parent()); 0315 0316 removeCommand->doCommand(); 0317 selection = m_treeView->selectionModel()->selection(); 0318 } 0319 } 0320 0321 void DynamicTreeWidget::insertSelected() 0322 { 0323 const QModelIndexList selectedRows = m_treeView->selectionModel()->selectedRows(); 0324 0325 if (selectedRows.size() != 1) { 0326 return; 0327 } 0328 0329 const QModelIndex selectedRow = selectedRows.first(); 0330 0331 ModelInsertCommand *ins = new ModelInsertCommand(m_dynamicTreeModel, this); 0332 if (m_insertChildren->isChecked()) { 0333 ins->setAncestorRowNumbers(m_dynamicTreeModel->indexToPath(selectedRow)); 0334 ins->setStartRow(0); 0335 } else if (m_insertSiblingsAbove->isChecked()) { 0336 ins->setAncestorRowNumbers(m_dynamicTreeModel->indexToPath(selectedRow.parent())); 0337 ins->setStartRow(selectedRow.row()); 0338 } else { 0339 Q_ASSERT(m_insertSiblingsBelow->isChecked()); 0340 ins->setAncestorRowNumbers(m_dynamicTreeModel->indexToPath(selectedRow.parent())); 0341 ins->setStartRow(selectedRow.row() + 1); 0342 } 0343 ins->interpret(m_insertPatternTextEdit->toPlainText()); 0344 ins->doCommand(); 0345 } 0346 0347 void DynamicTreeWidget::resetModel() 0348 { 0349 ModelResetCommand *resetCommand = new ModelResetCommand(m_dynamicTreeModel, this); 0350 0351 resetCommand->setInitialTree(m_insertPatternTextEdit->toPlainText().trimmed()); 0352 resetCommand->doCommand(); 0353 } 0354 0355 void DynamicTreeWidget::setTreePredefine(int index) 0356 { 0357 stringToModel(m_treePredefines->itemData(index).toString()); 0358 m_textEdit->setPlainText(modelTreeToString(0, QModelIndex())); 0359 } 0360 0361 void DynamicTreeWidget::setInsertSubTreePredefine(int index) 0362 { 0363 m_insertPatternTextEdit->setPlainText(m_insertSubTreePredefines->itemData(index).toString()); 0364 } 0365 0366 #include "moc_dynamictreewidget.cpp"