/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mappingtreewidget.h" #include "mappingtreemodel.h" #include "mappingtreeview.h" #include "mappingtreeproxy.h" #include "mappinginputdialog.h" #include "mappingdata.h" #include "smglobals.h" MappingTreeWidget::MappingTreeWidget(QWidget *parent) : QWidget(parent){ //setup model mModel = static_cast(SmGlobals::instance()->model("MappingTree")); mProxy = new MappingTreeProxy(this); mProxy->setSourceModel(mModel); mTypesModel = new QStringListModel(this); mTypesModel->setStringList(mModel->mappingTypeNames()); //setup gui mTree = new MappingTreeView; mTree->setModel(mProxy); mTree->setColumnHidden(1, true); mTree->setColumnHidden(2, true); mTree->setColumnHidden(3, true); mTree->setColumnHidden(4, true); mTree->setAlternatingRowColors(true); mTree->expandAll(); connect(mModel, &MappingTreeModel::needExpansion, mTree, &MappingTreeView::expandAll); connect(mTree->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MappingTreeWidget::selectionChanged); /* Hide buttons, this doesn't really work, * but keep them for future use :) */ mTypeBox = new QComboBox; mTypeBox->setModel(mTypesModel); connect(mTypeBox, QOverload::of(&QComboBox::currentIndexChanged), this, &MappingTreeWidget::typeChanged); mTypeBox->setHidden(true); mAddType = new QPushButton(tr("Add &type")); connect(mAddType, &QPushButton::clicked, this, &MappingTreeWidget::addType); mAddType->setHidden(true); mDeleteType = new QPushButton(tr("Delete type")); connect(mDeleteType, &QPushButton::clicked, this, &MappingTreeWidget::deleteType); mDeleteType->setHidden(true); QHBoxLayout *typesButtonLayout = new QHBoxLayout; typesButtonLayout->addWidget(mDeleteType); typesButtonLayout->addWidget(mAddType); //select type and populate model QSettings s; QString lastType = s.value("ui/mappingtreetype").toString(); if(lastType.isEmpty()){ if(!mTypesModel->stringList().isEmpty()){ lastType = mTypesModel->stringList().at(0); } } int typeId = mModel->mappingTypeIdFromName(lastType); if(typeId != -1){ mModel->setType(typeId); mTypeBox->setCurrentIndex(mTypeBox->findText(lastType)); typeChanged(lastType); } // filter + refresh mFilter = new QLineEdit; connect(mFilter, &QLineEdit::returnPressed, this, &MappingTreeWidget::filter); mDoFilter = new QPushButton(tr("Filter")); connect(mDoFilter, &QPushButton::clicked, this, &MappingTreeWidget::filter); mClearFilter = new QPushButton(tr("Clear")); connect(mClearFilter, &QPushButton::clicked, this, &MappingTreeWidget::clearFilter); mRefresh = new QPushButton; mRefresh->setIcon(QIcon(":/refresh.png")); connect(mRefresh, &QPushButton::clicked, mModel, &MappingTreeModel::populate); QLabel *filterLabel = new QLabel(tr("Filter")); QHBoxLayout *filterLayout = new QHBoxLayout; filterLayout->addWidget(filterLabel); filterLayout->addWidget(mFilter); filterLayout->addWidget(mDoFilter); filterLayout->addWidget(mClearFilter); filterLayout->addWidget(mRefresh); //setup actions mAddChildA = new QAction(tr("Add child..."), this); connect(mAddChildA, &QAction::triggered, this, &MappingTreeWidget::addChild); mTree->addAction(mAddChildA); mAddActorA = new QAction(tr("Add actor..."), this); mAddActorA->setShortcut(Qt::CTRL + Qt::Key_A); connect(mAddActorA, &QAction::triggered, this, &MappingTreeWidget::addActor); mTree->addAction(mAddActorA); mDeleteChildA = new QAction(tr("Delete..."), this); connect(mDeleteChildA, &QAction::triggered, this, &MappingTreeWidget::deleteChild); mTree->addAction(mDeleteChildA); mEditChildA = new QAction(tr("Edit..."), this); connect(mEditChildA, &QAction::triggered, this, &MappingTreeWidget::editChild); mTree->addAction(mEditChildA); //widget layout and misc QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(mTypeBox); mainLayout->addLayout(filterLayout); mainLayout->addLayout(typesButtonLayout); mainLayout->addWidget(mTree); setLayout(mainLayout); } MappingData MappingTreeWidget::selectedItem() const { QModelIndex sel = selected(); if(!sel.isValid()){ return MappingData(); } QModelIndex real = mProxy->mapToSource(sel); return mModel->mappingDataFromIndex(real); } QList MappingTreeWidget::selectedTree() const { QModelIndex start = selected(); QList retval; retval << selectedTreeRecursive(start); return retval; } QList MappingTreeWidget::selectedTreeRecursive(const QModelIndex &start) const{ QList retval; const QAbstractItemModel *startModel = start.model(); QModelIndex curChild = startModel->index(0, 0, start); if(!curChild.isValid()){ QModelIndex real = mProxy->mapToSource(start); retval << mModel->mappingDataFromIndex(real); return retval; } int row = 0; while(curChild.isValid()){ retval << selectedTreeRecursive(curChild); ++row; curChild = startModel->index(row, 0, start); } return retval; } void MappingTreeWidget::addChild(){ MappingInputDialog dlg(this); int retval = dlg.exec(); if(retval != QDialog::Accepted){ return; } QString value = dlg.mappingName(); if(value.isEmpty()){ return; } QModelIndex parent = mModel->rootIndex(); if(!dlg.createRoot()){ QModelIndex sel = selected(); parent = mProxy->mapToSource(sel); } int parentId = parent.data(MappingTreeModel::MappingIdRole).toInt(); if(!mModel->addChild(value, parent)){ QString err = QString(tr("

Failed to create child! Database said:

%1

")).arg(mModel->lastError().text()); QMessageBox::critical(this, tr("Error"), err); }else{ // we repopulated the model, so all indexes are invalid! QModelIndex newPIdx = mModel->findRecursive(parentId, MappingTreeModel::MappingId, mModel->rootIndex()); if(newPIdx.isValid()){ QModelIndex newSIdx = mModel->find(value, MappingTreeModel::Name, newPIdx); if(newSIdx.isValid()){ QModelIndex newSIdxP = mProxy->mapFromSource(newSIdx); mTree->scrollTo(newSIdxP, QAbstractItemView::EnsureVisible); mTree->selectionModel()->setCurrentIndex(newSIdxP, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current | QItemSelectionModel::Rows); } } } } void MappingTreeWidget::addActor(){ QModelIndex actorIndex = mModel->find("actors", MappingTreeModel::Name); if(!actorIndex.isValid()){ QMessageBox::critical(this, tr("Error"), tr("Could not find actors!")); return; } QString newActorName = QInputDialog::getText(this, tr("New actor"), tr("Actor")); if(!newActorName.isEmpty()){ QModelIndex newActorIdx = mModel->find(newActorName, MappingTreeModel::Name, actorIndex); if(newActorIdx.isValid()){ QModelIndex newIdxProxy = mProxy->mapFromSource(newActorIdx); mTree->scrollTo(newIdxProxy, QAbstractItemView::EnsureVisible); mTree->selectionModel()->setCurrentIndex(newIdxProxy, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current | QItemSelectionModel::Rows); }else{ mModel->addChild(newActorName, actorIndex); actorIndex = mModel->find("actors", MappingTreeModel::Name); QModelIndex newIdx = mModel->find(newActorName, MappingTreeModel::Name, actorIndex); if(newIdx.isValid()){ QModelIndex newIdxProxy = mProxy->mapFromSource(newIdx); mTree->scrollTo(newIdxProxy, QAbstractItemView::EnsureVisible); mTree->selectionModel()->setCurrentIndex(newIdxProxy, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current | QItemSelectionModel::Rows); } } } } void MappingTreeWidget::addType(){ QString typeName = QInputDialog::getText(this, tr("Enter type name"), tr("Name")).toLower().trimmed(); if(typeName.isEmpty()){ return; } if(mModel->addMappingType(typeName)){ mTypesModel->setStringList(mModel->mappingTypeNames()); int idxOf = mTypeBox->findText(typeName); if(idxOf != -1){ mTypeBox->setCurrentIndex(idxOf); } }else{ QMessageBox::critical(this, tr("Error"), tr("Failed to add type. Most likely it already exists!")); } } void MappingTreeWidget::deleteChild(){ QModelIndex sel = selected(); QModelIndex real = mProxy->mapToSource(sel); if(mModel->rowCount(real) > 0){ QString msg = QString(tr("Cannot delete item %1, because it has %2 children!")).arg(real.data().toString()).arg(QString::number(mModel->rowCount(real))); QMessageBox::critical(this, tr("Error"), msg); return; } QString question = QString(tr("Really delete %1?")).arg(real.data(MappingTreeModel::NameRole).toString()); int retval = QMessageBox::question(this, tr("Question"), question, QMessageBox::Yes | QMessageBox::No); if(retval == QMessageBox::Yes){ if(!mModel->deleteChild(real)){ QSqlError last = mModel->lastError(); QString msg = QString(tr("Failed to delete %1. Database said: %2")).arg(real.data().toString()).arg(last.text()); QMessageBox::critical(this, tr("Error"), msg); } } } void MappingTreeWidget::deleteType(){ QString curText = mTypeBox->currentText(); if(curText.isEmpty()){ return; } QString msg = QString(tr("Really delete %1?")).arg(curText); int retval = QMessageBox::question(this, tr("Question"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if(retval == QMessageBox::Yes){ int typeId = mModel->mappingTypeIdFromName(curText); if(typeId != -1){ if(mModel->deleteMappingType(typeId)){ mTypesModel->setStringList(mModel->mappingTypeNames()); if(mTypesModel->stringList().count() > 0){ mTypeBox->setCurrentIndex(0); } } } } } void MappingTreeWidget::hideEvent(QHideEvent *event){ QString type = mTypeBox->currentText(); if(!type.isEmpty()){ QSettings s; s.setValue("ui/mappingtreetype", type); } event->accept(); } void MappingTreeWidget::typeChanged(QString type){ int typeId = mModel->mappingTypeIdFromName(type); if(typeId != -1){ mModel->setType(typeId); mModel->populate(); mTree->expandAll(); } } void MappingTreeWidget::editChild(){ QModelIndex sel = selected(); QString question = QString("Rename %1").arg(sel.data(MappingTreeModel::NameRole).toString()); bool ok = false; QString newName = QInputDialog::getText(mTree, tr("Rename"), question, QLineEdit::Normal, sel.data(MappingTreeModel::NameRole).toString(), &ok); if(ok){ QModelIndex real = mProxy->mapToSource(sel); if(real.isValid()){ mModel->renameChild(real, newName); } } } void MappingTreeWidget::selectionChanged(){ QModelIndex sel = selected(); QModelIndex real = mProxy->mapToSource(sel); emit mappingChanged(real.data(MappingTreeModel::MappingIdRole).toInt()); } void MappingTreeWidget::filter(){ QString filter = mFilter->text(); mProxy->setFilter(filter); mTree->expandAll(); } void MappingTreeWidget::clearFilter(){ mFilter->clear(); mProxy->setFilter(QString()); mTree->expandAll(); } const QModelIndex MappingTreeWidget::selected() const{ QModelIndexList sel = mTree->selectionModel()->selectedRows(); if(sel.isEmpty()){ return QModelIndex(); } return sel.first(); }