diff --git a/keduvocdocument/CMakeLists.txt b/keduvocdocument/CMakeLists.txt index 373d6c0..b1a3ac1 100644 --- a/keduvocdocument/CMakeLists.txt +++ b/keduvocdocument/CMakeLists.txt @@ -1,141 +1,141 @@ if (BUILD_TESTING) add_subdirectory(autotests) add_subdirectory(tests) endif() ########### next target ############### include(ECMSetupVersion) ecm_setup_version(5.0.0 VARIABLE_PREFIX KDEEDU VERSION_HEADER "${CMAKE_BINARY_DIR}/keduvocdocument/keduvocdocument_version.h" PACKAGE_VERSION_FILE "${CMAKE_BINARY_DIR}/KEduVocDocumentVersion.cmake") include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) set(keduvocdocument_LIB_SRCS keduvocdocument.cpp keduvocidentifier.cpp keduvocexpression.cpp keduvoctranslation.cpp keduvoccontainer.cpp keduvoclesson.cpp keduvocleitnerbox.cpp keduvoctext.cpp keduvocarticle.cpp keduvocconjugation.cpp keduvocpersonalpronoun.cpp keduvocdeclension.cpp keduvocwordtype.cpp keduvockvtmlcompability.cpp keduvockvtml2writer.cpp keduvoccsvwriter.cpp - #keduvoccontainermodel.cpp + keduvoccontainermodel.cpp #keduvoclessonmodel.cpp keduvocreadonlycontainermodel.cpp keduvocvocabularymodel.cpp #keduvocwordclassmodel.cpp #keduvoccontainermimedata.cpp #keduvocvocabularymimedata.cpp readerwriters/dummyreader.cpp readerwriters/failedreader.cpp readerwriters/keduvockvtmlreader.cpp readerwriters/keduvockvtml2reader.cpp readerwriters/keduvoccsvreader.cpp readerwriters/keduvocpaukerreader.cpp readerwriters/keduvocvokabelnreader.cpp readerwriters/keduvocwqlreader.cpp readerwriters/keduvocxdxfreader.cpp readerwriters/readermanager.cpp sharedkvtmlfiles.cpp ) include(ECMGenerateHeaders) ecm_generate_headers( KdeEdu_HEADERS HEADER_NAMES KEduVocDocument KEduVocIdentifier KEduVocExpression KEduVocText KEduVocArticle KEduVocConjugation KEduVocLesson KEduVocLeitnerBox KEduVocContainer KEduVocWordFlags KEduVocMultipleChoice KEduVocTranslation KEduVocWordtype KEduVocPersonalPronoun SharedKVTMLFiles KEduVocDeclension KEduVocKVTML2Writer - #KEduVocContainerModel + KEduVocContainerModel #KEduVocLessonModel KEduVocReadOnlyContainerModel KEduVocVocabularyModel #KEduVocWordClassModel #KEduVocContainerMimeData #KEduVocVocabularyMimeData REQUIRED_HEADERS KdeEdu_HEADERS ) add_library(KEduVocDocument SHARED ${keduvocdocument_LIB_SRCS}) generate_export_header(KEduVocDocument BASE_NAME KEduVocDocument) # vHanda: Add library alias? target_link_libraries(KEduVocDocument PUBLIC Qt5::Xml PRIVATE KF5::I18n KF5::KIOCore KF5::Archive ) # vHanda: Add Export Name? set_target_properties(KEduVocDocument PROPERTIES VERSION ${KDEEDU_VERSION_STRING} SOVERSION ${KDEEDU_SOVERSION} ) target_include_directories(KEduVocDocument INTERFACE "$") #Library for non-api unittests add_library(keduvocdocument_static STATIC ${keduvocdocument_LIB_SRCS}) set_target_properties(keduvocdocument_static PROPERTIES COMPILE_FLAGS -DKEDUVOCDOCUMENT_STATIC_DEFINE) target_link_libraries(keduvocdocument_static PUBLIC KF5::KIOCore Qt5::Xml Qt5::Gui PRIVATE KF5::I18n KF5::Archive ) # if we want to set our own version instead of following kde generic #set(LIB_KEDUVOCDOCUMENT_VERSION "5.0.0") #set(LIB_KEDUVOCDOCUMENT_SOVERSION "5") #set_target_properties(keduvocdocument # PROPERTIES VERSION ${LIB_KEDUVOCDOCUMENT_VERSION} # SOVERSION ${LIB_KEDUVOCDOCUMENT_SOVERSION} #) install(TARGETS KEduVocDocument EXPORT LibKEduVocDocumentTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(FILES ${CMAKE_CURRENT_BINARY_DIR}/keduvocdocument_export.h ${KdeEdu_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libkeduvocdocument COMPONENT Devel ) diff --git a/keduvocdocument/keduvoccontainermodel.cpp b/keduvocdocument/keduvoccontainermodel.cpp new file mode 100644 index 0000000..af70cdb --- /dev/null +++ b/keduvocdocument/keduvoccontainermodel.cpp @@ -0,0 +1,335 @@ +/*************************************************************************** + + Copyright 2007-2008 Frederik Gladhorn + + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "keduvoccontainermodel.h" +#include "keduvoccontainer.h" + +#include "keduvoccontainermimedata.h" +#include "keduvocvocabularymimedata.h" + +#include +#include +#include +#include + +#include +#include + +/** @file + * Implementation of ContainerModel. + * Functions to create the model from the lessons of the vocabulary document. + */ + +KEduVocContainerModel::KEduVocContainerModel(KEduVocContainer::EnumContainerType type, QObject * parent) +: KEduVocReadonlyContainerModel(type, parent) +{ +} + +QModelIndex KEduVocContainerModel::appendContainer(const QModelIndex& parent, const QString & containerName) +{ + KEduVocContainer* parentContainer; + if (parent.isValid()) { + parentContainer = static_cast(parent.internalPointer()); + } else { + return QModelIndex(); + } + + beginInsertRows(parent, parentContainer->childContainerCount(), + parentContainer->childContainerCount()); + switch (getType()) { + case (KEduVocContainer::Lesson): + parentContainer->appendChildContainer(new KEduVocLesson(containerName, static_cast(parentContainer))); + break; + case (KEduVocContainer::WordType): { + KEduVocWordType* parentWordType = static_cast(parentContainer); + KEduVocWordType* wordTypeContainer = new KEduVocWordType(containerName, parentWordType); + wordTypeContainer->setWordType(parentWordType->wordType()); + parentContainer->appendChildContainer(wordTypeContainer); + break; + } + default: + break; + } + endInsertRows(); + + return index(parentContainer->childContainerCount() - 1, 0, parent); +} + + +QVariant KEduVocContainerModel::data(const QModelIndex & index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + KEduVocContainer *container = static_cast(index.internalPointer()); + + switch (index.column()) { + case ContainerNameColumn: + if (role == Qt::DisplayRole || role == Qt::EditRole) { + return container->name(); + } + + if (role == Qt::TextAlignmentRole) { + return Qt::AlignLeft; + } + break; + case TotalCountColumn: + if (role == Qt::DisplayRole) { + return container->entryCount(KEduVocContainer::Recursive); + } + if (role == Qt::TextAlignmentRole) { + return Qt::AlignRight; + } + break; + default: + if (role == Qt::TextAlignmentRole) { + return Qt::AlignRight; + } + } + + return QVariant(); +} + +bool KEduVocContainerModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid()) { + return false; + } + + if (index.column() == ContainerNameColumn) { + KEduVocContainer *container = static_cast(index.internalPointer()); + // rename a lesson + if (role == Qt::EditRole) { + container->setName(value.toString()); + emit dataChanged(index, index); + emit documentModified(); + return true; + } + + // checkboxes + if (role == Qt::CheckStateRole) { + bool newState = value.toBool(); + for (int i = 0; i < rowCount(index); i++) { + setData(index.child(i, 0), newState, Qt::CheckStateRole); + } + container->setInPractice(newState); + emit dataChanged(index, index); + emit documentModified(); + return true; + } + } + return false; +} + + +Qt::ItemFlags KEduVocContainerModel::flags(const QModelIndex &index) const +{ + if (index.isValid()) { + // the root element, not editable for now + if (index.parent() == QModelIndex()) { + return (Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } + // the name column + if (index.column() == ContainerNameColumn) { + return (Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable + | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); + } else { // every other element + return (Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); + } + } + return Qt::ItemIsDropEnabled; +} + + +QVariant KEduVocContainerModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + // statically two columns for now + if (orientation == Qt::Horizontal) { + switch (section) { + case ContainerNameColumn: + if (role == Qt::DisplayRole) { + return i18n("Unit"); + } + break; + case TotalCountColumn: + if (role == Qt::DisplayRole) { + return QVariant(); + } + if (role == Qt::ToolTipRole) { + return i18n("Number of entries in this lesson."); + } + break; + } + } + return QVariant(); +} + + +int KEduVocContainerModel::columnCount(const QModelIndex & parent) const +{ + Q_UNUSED(parent); + if (!getDoc()) { + return FirstDataColumn; + } + + // for now one grade per language + return FirstDataColumn; +} + + +void KEduVocContainerModel::deleteContainer(const QModelIndex & containerIndex) +{ + KEduVocContainer* container = static_cast(containerIndex.internalPointer()); + KEduVocContainer* parent = container->parent(); + + if (!parent) { + // never delete the root container + return; + } + + beginRemoveRows(containerIndex.parent(), containerIndex.row(), containerIndex.row()); + parent->deleteChildContainer(container->row()); + endRemoveRows(); +} + +Qt::DropActions KEduVocContainerModel::supportedDropActions() const +{ + return Qt::MoveAction | Qt::CopyAction; +} + +QStringList KEduVocContainerModel::mimeTypes() const +{ + return QStringList() << "text/plain"; +} + + +QMimeData * KEduVocContainerModel::mimeData(const QModelIndexList &indexes) const +{ + KEduVocContainerMimeData *mimeData = new KEduVocContainerMimeData(); + + foreach(const QModelIndex & index, indexes) { + mimeData->addContainer(static_cast(index.internalPointer())); + } + + mimeData->setText("Lesson"); + + return mimeData; +} + + +bool KEduVocContainerModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) +{ + Q_UNUSED(column) + + if (action == Qt::IgnoreAction) { + return true; + } + + // if it's internal, get the pointers + const KEduVocContainerMimeData * containerData = + qobject_cast(data); + + if (containerData) { + foreach(KEduVocContainer * container, containerData->containerList()) { + // no way to move a word type to a lesson for now + if (container->containerType() != getType()) { + return false; + } + + if (action == Qt::MoveAction || action == Qt::CopyAction) { + //qDebug() << "Move container: " << container->name(); + KEduVocContainer* parentContainer = 0; + + if (parent.isValid()) { + parentContainer = static_cast(parent.internalPointer()); + } + if (!parentContainer) { + // drop into root + parentContainer = rootContainer(); + } else { + //make sure a container cannot be dropped into one of its child containers! + KEduVocContainer* childTest = parentContainer; + while (childTest != 0) { + if (childTest == container) { + //qDebug() << "Cannot drop a container into one of its child containers!"; + return false; + } + childTest = childTest->parent(); + } + } + + QModelIndex oldParent = index(container->parent()); + + beginRemoveRows(oldParent, container->row(), container->row()); + container->parent()->removeChildContainer(container->row()); + endRemoveRows(); + + // if we get to choose, append seems sane. + if (row < 0) { + row = parentContainer->childContainerCount(); + } + + // use index because we sometimes reparent to the root container instead of dropping into nowhere + beginInsertRows(index(parentContainer), row, row); + parentContainer->insertChildContainer(row, container); + endInsertRows(); + + return true; + } + } + } + + // if it's a translation, get the pointers + const KEduVocVocabularyMimeData * translationData = + qobject_cast(data); + + if (translationData) { + if (!parent.isValid()) { + return false; + } + if (containerType() == KEduVocContainer::Lesson) { + // Create a list of the entries associated with the translations being copied. This prevents duplicates if they highlighted several columns. + QList entries; + + foreach(KEduVocTranslation * translation, translationData->translationList()) { + if (!entries.contains(translation->entry())) { + entries << translation->entry(); + } + } + + foreach(KEduVocExpression * entry, entries) { + static_cast(parent.internalPointer())->appendEntry(new KEduVocExpression(*entry)); + } + } + + if (containerType() == KEduVocContainer::WordType) { + foreach(KEduVocTranslation * translation, translationData->translationList()) { + translation->setWordType( + static_cast(parent.internalPointer())); + } + } + return false; + } + +// qDebug() << data->formats(); + + return false; +} + +Qt::DropActions KEduVocContainerModel::supportedDragActions() const +{ + return (Qt::CopyAction | Qt::MoveAction); +} \ No newline at end of file diff --git a/keduvocdocument/keduvoccontainermodel.h b/keduvocdocument/keduvoccontainermodel.h new file mode 100644 index 0000000..e364013 --- /dev/null +++ b/keduvocdocument/keduvoccontainermodel.h @@ -0,0 +1,82 @@ +/*************************************************************************** + + Copyright 2007-2008 Frederik Gladhorn + + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KEDUVOCCONTAINERMODEL_H +#define KEDUVOCCONTAINERMODEL_H + +#include "keduvocreadonlycontainermodel.h" + +#include +#include + +#include + +#include +#include + + +/** + * Model for the tree of containers (lessons, word types). + */ +class KEduVocContainerModel : public KEduVocReadonlyContainerModel +{ + Q_OBJECT + +public: + enum ColumnType { + ContainerNameColumn = 0, + TotalCountColumn, + FirstDataColumn + }; + + explicit KEduVocContainerModel(KEduVocContainer::EnumContainerType type, QObject *parent = 0); + + virtual QVariant data(const QModelIndex &index, int role) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + + virtual Qt::DropActions supportedDropActions() const; + virtual QStringList mimeTypes() const; + virtual QMimeData * mimeData(const QModelIndexList &indexes) const; + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent); + + /** Change the name or checkbox of a lesson. + * @param index which lesson + * @param value new name + * @param role + * @return bool @c true it worked */ + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + + QModelIndex appendContainer(const QModelIndex& parent, const QString & containerName = QString()); + + void deleteContainer(const QModelIndex& containerIndex); + + /** Indicate supported drag actions + @return enum of actions supported **/ + virtual Qt::DropActions supportedDragActions() const ; + +signals: + /** + * emitted when the inPractice state or name of a lesson changed. + */ + void documentModified(); +}; + + +#endif diff --git a/keduvocdocument/keduvocreadonlycontainermodel.cpp b/keduvocdocument/keduvocreadonlycontainermodel.cpp index 2eda6aa..1f48c20 100644 --- a/keduvocdocument/keduvocreadonlycontainermodel.cpp +++ b/keduvocdocument/keduvocreadonlycontainermodel.cpp @@ -1,207 +1,217 @@ /*************************************************************************** Copyright 2007-2008 Frederik Gladhorn ***************************************************************************/ /*************************************************************************** * * * 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 "keduvocreadonlycontainermodel.h" #include #include #include "keduvoccontainermimedata.h" #include "keduvocvocabularymimedata.h" #include #include #include #include class KEduVocReadonlyContainerModel::Private { public: KEduVocContainer::EnumContainerType m_type; KEduVocDocument *m_doc; Private(KEduVocContainer::EnumContainerType & type); }; KEduVocReadonlyContainerModel::Private::Private(KEduVocContainer::EnumContainerType & type) : m_type(type) , m_doc(0) { } /** @file * Implementation of ReadonlyContainerModel. * Functions to create the model from the lessons of the vocabulary document. */ KEduVocReadonlyContainerModel::KEduVocReadonlyContainerModel(KEduVocContainer::EnumContainerType & type, QObject * parent) : QAbstractItemModel( parent ) , d( new Private( type )) { } KEduVocReadonlyContainerModel::~KEduVocReadonlyContainerModel() { delete d; } +KEduVocContainer::EnumContainerType KEduVocReadonlyContainerModel::getType() const +{ + return d->m_type; +} + +KEduVocDocument* KEduVocReadonlyContainerModel::getDoc() const +{ + return d->m_doc; +} + void KEduVocReadonlyContainerModel::setDocument(KEduVocDocument * doc) { beginResetModel(); d->m_doc = doc; if (d->m_doc) { //qDebug() << "Set Document: " << d->m_doc->url(); } else { //qDebug() << "Set Invalid Document"; } endResetModel(); } QModelIndex KEduVocReadonlyContainerModel::index(int row, int column, const QModelIndex &parent) const { if (!d->m_doc || !hasIndex(row, column, parent)) { return QModelIndex(); } KEduVocContainer *parentContainer; if (!parent.isValid()) { parentContainer = 0; } else { parentContainer = static_cast(parent.internalPointer()); } KEduVocContainer *childContainer = 0; if (!parentContainer) { childContainer = rootContainer(); if (!childContainer) { return QModelIndex(); } } else { childContainer = parentContainer->childContainer(row); } return createIndex(row, column, childContainer); } QModelIndex KEduVocReadonlyContainerModel::index(KEduVocContainer * container) const { if (!container) { return QModelIndex(); } QModelIndex currentIndex = index(container->row(), 0, index(container->parent())); Q_ASSERT(container == currentIndex.internalPointer()); return currentIndex; } QModelIndex KEduVocReadonlyContainerModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } KEduVocContainer *childItem = static_cast(index.internalPointer()); if (!childItem) { return QModelIndex(); } KEduVocContainer *parentItem = childItem->parent(); if (!parentItem) { return QModelIndex(); } QModelIndex parentIndex = createIndex(parentItem->row(), 0, parentItem); return parentIndex; } int KEduVocReadonlyContainerModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) { return 0; } KEduVocContainer *parentItem; if (!parent.isValid()) { // root element if (!d->m_doc) { return 0; } return 1; } else { parentItem = static_cast(parent.internalPointer()); return parentItem->childContainerCount(); } } QVariant KEduVocReadonlyContainerModel::data(const QModelIndex & index, int role) const { if (!index.isValid()) { return QVariant(); } KEduVocContainer *container = static_cast(index.internalPointer()); switch (index.column()) { case 0: // Container name if (role == Qt::DisplayRole || role == Qt::EditRole) { if (index.parent() == QModelIndex()) { return i18n("None"); } return container->name(); } if (role == Qt::TextAlignmentRole) { return Qt::AlignLeft; } break; } return QVariant(); } Qt::ItemFlags KEduVocReadonlyContainerModel::flags(const QModelIndex &index) const { if (index.isValid()) { // the root element, not editable for now if (index.parent() == QModelIndex()) { return (Qt::ItemIsEnabled | Qt::ItemIsSelectable); } // the name column if (index.column() == 0) { return (Qt::ItemIsEnabled | Qt::ItemIsSelectable); } else { // every other element return (Qt::ItemIsEnabled | Qt::ItemIsSelectable); } } return 0; } int KEduVocReadonlyContainerModel::columnCount(const QModelIndex & parent) const { Q_UNUSED(parent); if (!d->m_doc) { return 1; } return 1; } KEduVocContainer::EnumContainerType KEduVocReadonlyContainerModel::containerType() { return d->m_type; } diff --git a/keduvocdocument/keduvocreadonlycontainermodel.h b/keduvocdocument/keduvocreadonlycontainermodel.h index d86545d..728198f 100644 --- a/keduvocdocument/keduvocreadonlycontainermodel.h +++ b/keduvocdocument/keduvocreadonlycontainermodel.h @@ -1,70 +1,74 @@ /*************************************************************************** Copyright 2007-2008 Frederik Gladhorn ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef KEDUVOCREADONLYCONTAINERMODEL_H #define KEDUVOCREADONLYCONTAINERMODEL_H #include #include #include #include #include /** * Model for the tree of containers (lessons, word types). * ReadonlyContainerModel is a read only tree model. * @see ContainerModel for its subclass that includes more options. */ class KEduVocReadonlyContainerModel : public QAbstractItemModel { Q_OBJECT public: explicit KEduVocReadonlyContainerModel(KEduVocContainer::EnumContainerType & type, QObject *parent = 0); ~KEduVocReadonlyContainerModel(); virtual QVariant data(const QModelIndex &index, int role) const; virtual Qt::ItemFlags flags(const QModelIndex &index) const; virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex index(KEduVocContainer* container) const; virtual QModelIndex parent(const QModelIndex &index) const; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; KEduVocContainer::EnumContainerType containerType(); + // getter methods + KEduVocContainer::EnumContainerType getType() const; + KEduVocDocument* getDoc() const; + public slots: /** Set the new source kvtml file * @param doc the new file */ virtual void setDocument(KEduVocDocument *doc); protected: virtual KEduVocContainer *rootContainer() const = 0; private: class Private; Private * const d; }; #endif diff --git a/keduvocdocument/keduvocvocabularymodel.cpp b/keduvocdocument/keduvocvocabularymodel.cpp index eecc1a5..052a6f5 100644 --- a/keduvocdocument/keduvocvocabularymodel.cpp +++ b/keduvocdocument/keduvocvocabularymodel.cpp @@ -1,408 +1,404 @@ /*************************************************************************** Copyright 2007 Frederik Gladhorn ***************************************************************************/ /*************************************************************************** * * * 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 "keduvocvocabularymodel.h" #include #include #include "keduvocvocabularymimedata.h" +#include "keduvocdocument.h" #include #include #include #include #include class KEduVocVocabularyModel::Private { public: Private(); KEduVocContainer *m_container; KEduVocLesson *m_lesson; KEduVocDocument *m_document; KEduVocContainer::EnumEntriesRecursive m_recursive; }; KEduVocVocabularyModel::Private::Private() { m_container = 0; m_document = 0; m_lesson = 0; - m_recursive = 0; } KEduVocVocabularyModel::KEduVocVocabularyModel(bool show, QObject *parent) : QAbstractTableModel(parent), d( new Private ) { setRecursive(show); qRegisterMetaType("KEduVocTranslationPointer"); } KEduVocVocabularyModel::~KEduVocVocabularyModel() { delete d; } void KEduVocVocabularyModel::setDocument(KEduVocDocument * doc) { beginResetModel(); - d->m_document = doc; - d->m_container = 0; - d->m_lesson = 0; - if (d->m_document) { showContainer(d->m_document->lesson()); } else { showContainer(0); } endResetModel(); } void KEduVocVocabularyModel::showContainer(KEduVocContainer * container) { // use remove and insert rows. using reset resets all table headers too. if (rowCount(QModelIndex()) > 0) { beginRemoveRows(QModelIndex(), 0, rowCount(QModelIndex()) - 1); d->m_container = 0; endRemoveRows(); } if (container) { if (container->entryCount(d->m_recursive) > 0) { beginInsertRows(QModelIndex(), 0, container->entryCount(d->m_recursive) - 1); d->m_container = container; endInsertRows(); } else { d->m_container = container; } } } void KEduVocVocabularyModel::setLesson(KEduVocLesson * lessonContainer) { d->m_lesson = lessonContainer; } KEduVocLesson * KEduVocVocabularyModel::lesson() { return d->m_lesson; } KEduVocContainer::EnumEntriesRecursive KEduVocVocabularyModel::recursive() { return d->m_recursive; } int KEduVocVocabularyModel::rowCount(const QModelIndex &index) const { // no lesson set - zarro rows if (!d->m_container) { return 0; } // only the root index has children because we have no hierarchical model. if (index == QModelIndex()) { return d->m_container->entryCount(d->m_recursive); } return 0; } int KEduVocVocabularyModel::columnCount(const QModelIndex &) const { if (!d->m_document) { return 0; } return d->m_document->identifierCount() * EntryColumnsMAX; } QVariant KEduVocVocabularyModel::data(const QModelIndex & index, int role) const { if (!d->m_document || !d->m_container) { return QVariant(); } int translationId = translation(index.column()); int entryColumn = columnType(index.column()); switch (role) { case Qt::DisplayRole: switch (entryColumn) { case Translation: return QVariant(d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->text()); case Pronunciation: return QVariant(d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->pronunciation()); case WordClass: // if no word type is set, we get a null pointer if (d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->wordType()) { return QVariant(d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->wordType()->name()); } return QVariant(QString()); case Synonym: { QStringList displayElements; foreach(KEduVocTranslation * synonym, d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->synonyms()) { displayElements.append(synonym->text()); } return QVariant(displayElements.join("; ")); } case Antonym: { QStringList displayElements; foreach(KEduVocTranslation * antonym, d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->antonyms()) { displayElements.append(antonym->text()); } return QVariant(displayElements.join("; ")); } case Example: { QString example = d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->example(); return QVariant(example); } case Comment: return QVariant(d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->comment()); case Paraphrase: return QVariant(d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->paraphrase()); default: return QVariant(); } break; case Qt::FontRole: if (entryColumn == Translation) { QString locale = d->m_document->identifier(translationId).locale(); LanguageSettings ls(locale); ls.load(); return ls.editorFont(); } return QVariant(); case LocaleRole: return QVariant(d->m_document->identifier(translationId).locale()); case AudioRole: return QVariant(d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->soundUrl()); case ImageRole: return QVariant(d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->imageUrl()); case EntryRole: { QVariant v; v.setValue(d->m_container->entry(index.row(), d->m_recursive)); return v; } case Qt::ToolTipRole: { ///@todo more tooltips? switch (entryColumn) { case WordClass: return i18n("You can drag and drop words onto their word type."); case Synonym: return i18n("Enable the synonym view to edit synonyms."); case Antonym: return i18n("Enable the antonym view to edit antonyms."); } } } return QVariant(); } bool KEduVocVocabularyModel::setData(const QModelIndex &index, const QVariant &value, int role) { if ((!index.isValid()) || (role != Qt::EditRole)) { return false; } int translationId = translation(index.column()); int column = columnType(index.column()); switch (column) { case Translation: d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->setText(value.toString()); break; case Pronunciation: d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->setPronunciation(value.toString()); break; case WordClass: break; case Example: d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->setExample(value.toString()); break; case Comment: d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->setComment(value.toString()); break; case Paraphrase: d->m_container->entry(index.row(), d->m_recursive)->translation(translationId)->setParaphrase(value.toString()); break; default: return false; } emit(dataChanged(index, index)); ///@todo trust dirty bit d->m_document->setModified(); return true; } Qt::ItemFlags KEduVocVocabularyModel::flags(const QModelIndex & index) const { if (!index.isValid()) { return Qt::ItemIsDropEnabled; } switch (columnType(index.column())) { case Translation: return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; case WordClass: return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; case Synonym: case Antonym: return QAbstractItemModel::flags(index) | Qt::ItemIsDropEnabled; default: return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDropEnabled; } } QVariant KEduVocVocabularyModel::headerData(int section, Qt::Orientation orientation, int role) const { if (!d->m_document) { return QVariant(); } if (orientation == Qt::Horizontal) { int translationId = section / EntryColumnsMAX; int entryColumn = section % EntryColumnsMAX; switch (role) { case Qt::DisplayRole: return KEduVocVocabularyModel::columnTitle(d->m_document, translationId, entryColumn); break; } // switch role } // if horizontal return QVariant(); } QString KEduVocVocabularyModel::columnTitle(KEduVocDocument *document, int translation, int column) { switch (column) { case Translation: if (document->identifierCount() - 1 < translation) { return QString(); } return document->identifier(translation).name(); //returns "English", "German", etc case Pronunciation: return i18n("Pronunciation"); case WordClass: return i18n("Word Type"); case Synonym: return i18n("Synonym"); case Antonym: return i18n("Antonym"); case Example: return i18n("Example"); case Comment: return i18n("Comment"); case Paraphrase: return i18n("Paraphrase"); } return QString(); } int KEduVocVocabularyModel::translation(int column) { return column / EntryColumnsMAX; } int KEduVocVocabularyModel::columnType(int column) { return column % EntryColumnsMAX; } QModelIndex KEduVocVocabularyModel::appendEntry(KEduVocExpression *expression) { if (d->m_document->identifierCount() == 0) { return QModelIndex(); } if (!d->m_lesson || !d->m_lesson->parent()) { return QModelIndex(); } beginInsertRows(QModelIndex(), rowCount(QModelIndex()), rowCount(QModelIndex())); if (!expression) { expression = new KEduVocExpression; } d->m_lesson->appendEntry(expression); endInsertRows(); return index(rowCount(QModelIndex()) - 1, 0, QModelIndex()); } bool KEduVocVocabularyModel::removeRows(int row, int count, const QModelIndex & parent) { Q_UNUSED(parent); if (count < 1 || row < 0 || row + count > d->m_container->entryCount(d->m_recursive)) { return false; } int bottomRow = row + count - 1; beginRemoveRows(QModelIndex(), row, bottomRow); for (int i = bottomRow; i >= row; i--) { delete d->m_container->entry(i, d->m_recursive); } endRemoveRows(); return true; } QStringList KEduVocVocabularyModel::mimeTypes() const { return QStringList() << "text/plain"; } QMimeData * KEduVocVocabularyModel::mimeData(const QModelIndexList & indexes) const { VocabularyMimeData *mimeData = new VocabularyMimeData(); QModelIndexList sortedIndexes = indexes; qSort(sortedIndexes); //qDebug() << "mimeData for " << indexes.count() << "indexes"; QList translations; foreach(const QModelIndex & index, sortedIndexes) { // only add if it's a translation. other cells like word type are being ignored for now. if (columnType(index.column()) == Translation) { translations.append(d->m_container->entry(index.row(), d->m_recursive)->translation(translation(index.column()))); } } mimeData->setTranslations(translations); return mimeData; } void KEduVocVocabularyModel::setRecursive(bool show) { beginResetModel(); if (show) { d->m_recursive = KEduVocContainer::Recursive; } else { d->m_recursive = KEduVocContainer::NotRecursive; } endResetModel(); } void KEduVocVocabularyModel::resetLanguages() { // play it save - this happens seldom enough to warrant a reload setDocument(d->m_document); } \ No newline at end of file