File indexing completed on 2024-04-14 03:49:03
0001 /* 0002 SPDX-FileCopyrightText: 2007-2008 Frederik Gladhorn <frederik.gladhorn@kdemail.net> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "containermodel.h" 0007 0008 #include "containermimedata.h" 0009 #include "vocabularymimedata.h" 0010 0011 #include <KEduVocExpression> 0012 #include <KEduVocWordtype> 0013 0014 #include <KLocalizedString> 0015 #include <QDebug> 0016 0017 /** @file 0018 * Implementation of ContainerModel. 0019 * Functions to create the model from the lessons of the vocabulary document. 0020 */ 0021 0022 ContainerModel::ContainerModel(KEduVocContainer::EnumContainerType type, QObject *parent) 0023 : ReadonlyContainerModel(type, parent) 0024 { 0025 m_type = type; 0026 } 0027 0028 QModelIndex ContainerModel::appendContainer(const QModelIndex &parent, const QString &containerName) 0029 { 0030 KEduVocContainer *parentContainer; 0031 if (parent.isValid()) { 0032 parentContainer = static_cast<KEduVocContainer *>(parent.internalPointer()); 0033 } else { 0034 return QModelIndex(); 0035 } 0036 0037 beginInsertRows(parent, parentContainer->childContainerCount(), parentContainer->childContainerCount()); 0038 switch (m_type) { 0039 case (KEduVocContainer::Lesson): 0040 parentContainer->appendChildContainer(new KEduVocLesson(containerName, static_cast<KEduVocLesson *>(parentContainer))); 0041 break; 0042 case (KEduVocContainer::WordType): { 0043 KEduVocWordType *parentWordType = static_cast<KEduVocWordType *>(parentContainer); 0044 KEduVocWordType *wordTypeContainer = new KEduVocWordType(containerName, parentWordType); 0045 wordTypeContainer->setWordType(parentWordType->wordType()); 0046 parentContainer->appendChildContainer(wordTypeContainer); 0047 break; 0048 } 0049 default: 0050 break; 0051 } 0052 endInsertRows(); 0053 0054 return index(parentContainer->childContainerCount() - 1, 0, parent); 0055 } 0056 0057 QVariant ContainerModel::data(const QModelIndex &index, int role) const 0058 { 0059 if (!index.isValid()) { 0060 return QVariant(); 0061 } 0062 0063 KEduVocContainer *container = static_cast<KEduVocContainer *>(index.internalPointer()); 0064 0065 switch (index.column()) { 0066 case ContainerNameColumn: 0067 if (role == Qt::DisplayRole || role == Qt::EditRole) { 0068 return container->name(); 0069 } 0070 0071 // if (role == Qt::DecorationRole) { 0072 // return QIcon::fromTheme("favorites"); 0073 // } 0074 if (role == Qt::TextAlignmentRole) { 0075 return Qt::AlignLeft; 0076 } 0077 break; 0078 case TotalCountColumn: 0079 if (role == Qt::DisplayRole) { 0080 return container->entryCount(KEduVocContainer::Recursive); 0081 } 0082 if (role == Qt::TextAlignmentRole) { 0083 return Qt::AlignRight; 0084 } 0085 break; 0086 default: 0087 if (role == Qt::TextAlignmentRole) { 0088 return Qt::AlignRight; 0089 } 0090 } 0091 0092 return QVariant(); 0093 } 0094 0095 bool ContainerModel::setData(const QModelIndex &index, const QVariant &value, int role) 0096 { 0097 if (!index.isValid()) { 0098 return false; 0099 } 0100 0101 if (index.column() == ContainerNameColumn) { 0102 KEduVocContainer *container = static_cast<KEduVocContainer *>(index.internalPointer()); 0103 // rename a lesson 0104 if (role == Qt::EditRole) { 0105 container->setName(value.toString()); 0106 Q_EMIT dataChanged(index, index); 0107 Q_EMIT documentModified(); 0108 return true; 0109 } 0110 0111 // checkboxes 0112 if (role == Qt::CheckStateRole) { 0113 bool newState = value.toBool(); 0114 for (int i = 0; i < rowCount(index); i++) { 0115 setData(index.model()->index(i, 0, index), newState, Qt::CheckStateRole); 0116 } 0117 container->setInPractice(newState); 0118 Q_EMIT dataChanged(index, index); 0119 Q_EMIT documentModified(); 0120 return true; 0121 } 0122 } 0123 return false; 0124 } 0125 0126 Qt::ItemFlags ContainerModel::flags(const QModelIndex &index) const 0127 { 0128 if (index.isValid()) { 0129 // the root element, not editable for now 0130 if (index.parent() == QModelIndex()) { 0131 return (Qt::ItemIsEnabled | Qt::ItemIsSelectable); 0132 } 0133 // the name column 0134 if (index.column() == ContainerNameColumn) { 0135 return (Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); 0136 } else { // every other element 0137 return (Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); 0138 } 0139 } 0140 return Qt::ItemIsDropEnabled; 0141 } 0142 0143 QVariant ContainerModel::headerData(int section, Qt::Orientation orientation, int role) const 0144 { 0145 // statically two columns for now 0146 if (orientation == Qt::Horizontal) { 0147 switch (section) { 0148 case ContainerNameColumn: 0149 if (role == Qt::DisplayRole) { 0150 return i18n("Unit"); 0151 } 0152 break; 0153 case TotalCountColumn: 0154 if (role == Qt::DisplayRole) { 0155 return QVariant(); 0156 } 0157 if (role == Qt::ToolTipRole) { 0158 return i18n("Number of entries in this lesson."); 0159 } 0160 break; 0161 } 0162 } 0163 return QVariant(); 0164 } 0165 0166 int ContainerModel::columnCount(const QModelIndex &parent) const 0167 { 0168 Q_UNUSED(parent); 0169 if (!m_doc) { 0170 return FirstDataColumn; 0171 } 0172 0173 // for now one grade per language 0174 return FirstDataColumn; // + m_doc->identifierCount(); 0175 } 0176 0177 void ContainerModel::deleteContainer(const QModelIndex &containerIndex) 0178 { 0179 KEduVocContainer *container = static_cast<KEduVocContainer *>(containerIndex.internalPointer()); 0180 KEduVocContainer *parent = container->parent(); 0181 0182 if (!parent) { 0183 // never delete the root container 0184 return; 0185 } 0186 0187 beginRemoveRows(containerIndex.parent(), containerIndex.row(), containerIndex.row()); 0188 parent->deleteChildContainer(container->row()); 0189 endRemoveRows(); 0190 } 0191 0192 Qt::DropActions ContainerModel::supportedDropActions() const 0193 { 0194 return Qt::MoveAction | Qt::CopyAction; 0195 } 0196 0197 QStringList ContainerModel::mimeTypes() const 0198 { 0199 return QStringList() << QStringLiteral("text/plain"); 0200 } 0201 0202 QMimeData *ContainerModel::mimeData(const QModelIndexList &indexes) const 0203 { 0204 ContainerMimeData *mimeData = new ContainerMimeData(); 0205 // QByteArray encodedData; 0206 0207 for (const QModelIndex &index : indexes) { 0208 mimeData->addContainer(static_cast<KEduVocContainer *>(index.internalPointer())); 0209 } 0210 mimeData->setText(QStringLiteral("Parley lesson")); 0211 0212 // QDataStream stream(&encodedData, QIODevice::WriteOnly); 0213 // stream << "Parley lesson"; 0214 // for (const QModelIndex &index : qAsConst(indexes)) { 0215 // if (index.isValid()) { 0216 // QString text = data(index, Qt::DisplayRole).toString(); 0217 // stream << text; 0218 // } 0219 // } 0220 // // qDebug() << "mimeData:" << encodedData; 0221 // mimeData->setData("text/plain", encodedData); 0222 return mimeData; 0223 } 0224 0225 bool ContainerModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) 0226 { 0227 Q_UNUSED(column) 0228 0229 if (action == Qt::IgnoreAction) { 0230 return true; 0231 } 0232 0233 // if it's internal, get the pointers 0234 const ContainerMimeData *containerData = qobject_cast<const ContainerMimeData *>(data); 0235 0236 if (containerData) { 0237 const QList<KEduVocContainer *> containerList = containerData->containerList(); 0238 for (KEduVocContainer *container : containerList) { 0239 // no way to move a word type to a lesson for now 0240 if (container->containerType() != m_type) { 0241 return false; 0242 } 0243 0244 if (action == Qt::MoveAction || action == Qt::CopyAction) { 0245 qDebug() << "Move container: " << container->name(); 0246 KEduVocContainer *parentContainer = nullptr; 0247 0248 if (parent.isValid()) { 0249 parentContainer = static_cast<KEduVocContainer *>(parent.internalPointer()); 0250 } 0251 if (!parentContainer) { 0252 // drop into root 0253 parentContainer = rootContainer(); 0254 } else { 0255 // make sure a container cannot be dropped into one of its child containers! 0256 KEduVocContainer *childTest = parentContainer; 0257 while (childTest != nullptr) { 0258 if (childTest == container) { 0259 qDebug() << "Cannot drop a container into one of its child containers!"; 0260 return false; 0261 } 0262 childTest = childTest->parent(); 0263 } 0264 } 0265 0266 QModelIndex oldParent = index(container->parent()); 0267 0268 beginRemoveRows(oldParent, container->row(), container->row()); 0269 container->parent()->removeChildContainer(container->row()); 0270 endRemoveRows(); 0271 0272 // if we get to choose, append seems sane. 0273 if (row < 0) { 0274 row = parentContainer->childContainerCount(); 0275 } 0276 0277 // use index because we sometimes reparent to the root container instead of dropping into nowhere 0278 beginInsertRows(index(parentContainer), row, row); 0279 parentContainer->insertChildContainer(row, container); 0280 endInsertRows(); 0281 0282 return true; 0283 } 0284 } 0285 } 0286 0287 // if it's a translation, get the pointers 0288 const VocabularyMimeData *translationData = qobject_cast<const VocabularyMimeData *>(data); 0289 0290 if (translationData) { 0291 if (!parent.isValid()) { 0292 return false; 0293 } 0294 if (containerType() == KEduVocContainer::Lesson) { 0295 // Create a list of the entries associated with the translations being copied. This prevents duplicates if they highlighted several columns. 0296 QList<KEduVocExpression *> entries; 0297 0298 const QList<KEduVocTranslation *> translationList = translationData->translationList(); 0299 for (const auto &translation : translationList) { 0300 if (!entries.contains(translation->entry())) { 0301 entries << translation->entry(); 0302 } 0303 } 0304 0305 for (KEduVocExpression *entry : qAsConst(entries)) { 0306 static_cast<KEduVocLesson *>(parent.internalPointer())->appendEntry(new KEduVocExpression(*entry)); 0307 } 0308 } 0309 0310 if (containerType() == KEduVocContainer::WordType) { 0311 const QList<KEduVocTranslation *> translationList = translationData->translationList(); 0312 for (const auto &translation : translationList) { 0313 translation->setWordType(static_cast<KEduVocWordType *>(parent.internalPointer())); 0314 } 0315 } 0316 return false; 0317 } 0318 0319 qDebug() << data->formats(); 0320 /* 0321 if (data->hasText()) { 0322 if (action == Qt::CopyAction | action == Qt::MoveAction) { 0323 QString name; 0324 name = data->text(); 0325 qDebug() << "Copy lesson " << name; 0326 0327 appendLesson(parent, name); 0328 return true; 0329 } 0330 }*/ 0331 0332 return false; 0333 } 0334 0335 Qt::DropActions ContainerModel::supportedDragActions() const 0336 { 0337 return (Qt::CopyAction | Qt::MoveAction); 0338 } 0339 0340 /* 0341 bool ContainerModel::removeRows(int row, int count, const QModelIndex & parent) 0342 { 0343 // BIG FAT WARNING this code works, but it gets called by the drag and drop implementation automatically, so either this gets used or the other (dropMimeData) 0344 to remove the containers. If both are active, containers get deleted without warning or visible signs. 0345 0346 KEduVocContainer* parentContainer; 0347 if (!parent.internalPointer()) { 0348 parentContainer = m_container; 0349 } else { 0350 parentContainer = static_cast<KEduVocContainer*>(parent.internalPointer()); 0351 } 0352 qDebug() << "removeRows from " << parentContainer->name() << " row " << row << "count" << count; 0353 0354 beginRemoveRows ( parent, row, row+count ); 0355 for (int i = 0; i<count; i++) { 0356 parentContainer->removeChildContainer(row); 0357 } 0358 endRemoveRows(); 0359 0360 return true; 0361 } 0362 0363 */ 0364 0365 #include "moc_containermodel.cpp"