diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9a12c50..86a65993 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,199 +1,199 @@ include_directories( ${parley_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/collection ${CMAKE_CURRENT_SOURCE_DIR}/editor # FIXME: Remove when moving the rest of the files in vocabulary/ ) # installation of kconfig files .kcfg containing app settings add_subdirectory( settings ) set(parley_LIB_SRCS parleyactions.cpp parleydocument.cpp parleymainwindow.cpp utils.cpp collection/collection.cpp collection/testentry.cpp collection/entryfilter.cpp collection/entryfilterdialog.cpp collection/vocabularymimedata.cpp collection/containermimedata.cpp - collection/readonlycontainermodel.cpp + #collection/readonlycontainermodel.cpp collection/containermodel.cpp collection/lessonmodel.cpp #collection/vocabularymodel.cpp collection/vocabularyfilter.cpp collection/wordclassmodel.cpp collection/containerview.cpp editor/editor.cpp editor/vocabularycolumnsdialog.cpp editor/lessonview.cpp editor/vocabularydelegate.cpp editor/vocabularyheaderview.cpp editor/vocabularyview.cpp editor/wordtypeview.cpp editor/audiowidget.cpp editor/browserwidget.cpp editor/comparisonwidget.cpp editor/inflectionwidget.cpp editor/conjugationwidget.cpp editor/declensionwidget.cpp editor/imagechooserwidget.cpp editor/multiplechoicewidget.cpp editor/summarywordwidget.cpp editor/synonymwidget.cpp editor/latexwidget.cpp practice/abstractwidget.cpp practice/sessionmanagerbase.cpp practice/sessionmanagercontinuous.cpp practice/sessionmanagerfixed.cpp practice/abstractfrontend.cpp practice/abstractbackendmode.cpp practice/practicestatemachine.cpp practice/comparisonbackendmode.cpp practice/comparisonmodewidget.cpp practice/conjugationbackendmode.cpp practice/conjugationmodewidget.cpp practice/guifrontend.cpp practice/writtenpracticewidget.cpp practice/writtenpracticevalidator.cpp practice/writtenbackendmode.cpp practice/examplesentencebackendmode.cpp practice/flashcardmodewidget.cpp practice/flashcardbackendmode.cpp practice/multiplechoicemodewidget.cpp practice/multiplechoicebackendmode.cpp practice/genderbackendmode.cpp practice/mixedlettersmodewidget.cpp practice/imagewidget.cpp practice/practicemainwindow.cpp practice/practicesummarycomponent.cpp practice/boxeswidget.cpp practice/audiobutton.cpp practice/summarybarwidget.cpp practice/themedbackgroundrenderer.cpp practice/imagecache.cpp practice/statustoggle.cpp practice/statustogglebutton.cpp practice/latexrenderer.cpp practice/configure/configurepracticedialog.cpp practice/configure/generalpracticeoptions.cpp practice/configure/blockoptions.cpp practice/configure/thresholdoptions.cpp practice/configure/specificpracticeoptions.cpp scripts/scriptdialog.cpp scripts/scriptmanager.cpp scripts/scripting/parley.cpp scripts/scripting/document.cpp scripts/scripting/lesson.cpp scripts/scripting/expression.cpp scripts/scripting/translation.cpp scripts/scripting/text.cpp scripts/scripting/container.cpp scripts/scripting/identifier.cpp scripts/script.cpp scripts/translator.cpp settings/generaloptions.cpp settings/parleyprefs.cpp settings/viewoptions.cpp settings/documentproperties.cpp settings/languageproperties.cpp settings/languagepropertiespage.cpp settings/kgametheme/kgametheme.cpp settings/kgametheme/kgamethemeselector.cpp statistics/conjugationoptions.cpp statistics/lessonstatisticsview.cpp statistics/statisticsmodel.cpp statistics/statisticsmainwindow.cpp statistics/statisticslegendwidget.cpp dashboard/dashboard.cpp dashboard/buttondelegate.cpp dashboard/gradereferencewidget.cpp dashboard/barwidget.cpp dashboard/collectionwidget.cpp ) ki18n_wrap_ui(parley_LIB_SRCS collection/entryfilterdialog.ui editor/multiplechoicewidget.ui editor/comparisonwidget.ui editor/conjugationwidget.ui editor/declensionwidget.ui editor/imagechooserwidget.ui editor/audiowidget.ui editor/synonymwidget.ui editor/browserwidget.ui editor/summarywordwidget.ui editor/latexwidget.ui practice/practicesummarywidget.ui practice/practice_mainwindow.ui practice/practice_widget_comparison.ui practice/practice_widget_conjugation.ui practice/practice_widget_flashcard.ui practice/practice_widget_multiplechoice.ui practice/practice_widget_written.ui practice/configure/generalpracticeoptions.ui practice/configure/blockoptions.ui practice/configure/thresholdoptions.ui practice/configure/specificpracticeoptions.ui settings/optionlistform.ui settings/viewoptionsbase.ui settings/generaloptionsbase.ui settings/languagepropertiespage.ui settings/documentproperties.ui settings/kgametheme/kgamethemeselector.ui statistics/statisticsmainwindow.ui dashboard/dashboard.ui ) kconfig_add_kcfg_files(parley_LIB_SRCS settings/prefs.kcfgc settings/documentsettings.kcfgc settings/languagesettings.kcfgc ) qt5_add_dbus_adaptor(parley_LIB_SRCS editor/org.kde.parley.xml editor/editor.h Editor::EditorWindow) #### XSLT Support #### # to transform the document xml to html or other if(HAVE_LIBXSLT) set(parley_LIB_SRCS ${parley_LIB_SRCS} exportdialog.cpp ) ki18n_wrap_ui(parley_LIB_SRCS exportdialog.ui ) endif(HAVE_LIBXSLT) #### End XSLT Support #### # This library is used both by parley itself and the unit tests. add_library(parley_LIB STATIC ${parley_LIB_SRCS}) set(parley_SRCS main.cpp) add_executable(parley ${parley_SRCS}) target_link_libraries(parley parley_LIB ${parley_LINK_LIBS}) target_link_libraries(parley_LIB ${parley_LINK_LIBS}) ########### install files ############### install(TARGETS parley ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) # desktop files appear in the menus install( PROGRAMS org.kde.parley.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) # hot new stuff config install( FILES parley.knsrc parley-themes.knsrc DESTINATION ${KDE_INSTALL_CONFDIR} ) # UI files - define menus and toolbars # @todo frameworks find a definitive locations for files and then use KXMLGUI_INSTALL_DIR install( FILES parleyui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/parley ) #install( FILES editor/editorui.rc DESTINATION ${KDE_INSTALL_DATADIR}/parley ) install( FILES editor/editorui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/parley ) install( FILES dashboard/dashboardui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/parley ) # install( FILES statistics/statisticsui.rc DESTINATION ${KDE_INSTALL_DATADIR}/parley ) # install( FILES practice/practiceui.rc DESTINATION ${KDE_INSTALL_DATADIR}/parley ) # install( FILES practice/practicesummaryui.rc DESTINATION ${KDE_INSTALL_DATADIR}/parley ) install( FILES statistics/statisticsui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/parley ) install( FILES practice/practiceui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/parley ) install( FILES practice/practicesummaryui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/parley ) diff --git a/src/collection/containermodel.cpp b/src/collection/containermodel.cpp index a95ca690..01caa1b0 100644 --- a/src/collection/containermodel.cpp +++ b/src/collection/containermodel.cpp @@ -1,389 +1,388 @@ /*************************************************************************** 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 "containermodel.h" #include "containermimedata.h" #include "vocabularymimedata.h" #include #include #include #include #include #include /** @file * Implementation of ContainerModel. * Functions to create the model from the lessons of the vocabulary document. */ ContainerModel::ContainerModel(KEduVocContainer::EnumContainerType type, QObject * parent) - : ReadonlyContainerModel(type, parent) + : KEduVocReadonlyContainerModel(type, parent) { - m_type = type; - m_doc = 0; + setDocument(0); } QModelIndex ContainerModel::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 (m_type) { + switch (containerType()) { 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 ContainerModel::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::DecorationRole) { // return QIcon::fromTheme("favorites"); // } 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 ContainerModel::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.model()->index(i, 0, index), newState, Qt::CheckStateRole); } container->setInPractice(newState); emit dataChanged(index, index); emit documentModified(); return true; } } return false; } Qt::ItemFlags ContainerModel::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 ContainerModel::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 ContainerModel::columnCount(const QModelIndex & parent) const { Q_UNUSED(parent); - if (!m_doc) { + if (!document()) { return FirstDataColumn; } // for now one grade per language return FirstDataColumn; // + m_doc->identifierCount(); } void ContainerModel::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 ContainerModel::supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; } QStringList ContainerModel::mimeTypes() const { return QStringList() << QStringLiteral("text/plain"); } QMimeData * ContainerModel::mimeData(const QModelIndexList &indexes) const { ContainerMimeData *mimeData = new ContainerMimeData(); // QByteArray encodedData; foreach(const QModelIndex & index, indexes) { mimeData->addContainer(static_cast(index.internalPointer())); } mimeData->setText(QStringLiteral("Parley lesson")); // QDataStream stream(&encodedData, QIODevice::WriteOnly); // stream << "Parley lesson"; // foreach (const QModelIndex &index, indexes) { // if (index.isValid()) { // QString text = data(index, Qt::DisplayRole).toString(); // stream << text; // } // } // // qDebug() << "mimeData:" << encodedData; // mimeData->setData("text/plain", encodedData); return mimeData; } bool ContainerModel::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 ContainerMimeData * 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() != m_type) { + if (container->containerType() != containerType()) { 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 VocabularyMimeData * 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(); /* if (data->hasText()) { if (action == Qt::CopyAction | action == Qt::MoveAction) { QString name; name = data->text(); qDebug() << "Copy lesson " << name; appendLesson(parent, name); return true; } }*/ return false; } Qt::DropActions ContainerModel::supportedDragActions() const { return (Qt::CopyAction | Qt::MoveAction); } /* bool ContainerModel::removeRows(int row, int count, const QModelIndex & parent) { // 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) to remove the containers. If both are active, containers get deleted without warning or visible signs. KEduVocContainer* parentContainer; if (!parent.internalPointer()) { parentContainer = m_container; } else { parentContainer = static_cast(parent.internalPointer()); } qDebug() << "removeRows from " << parentContainer->name() << " row " << row << "count" << count; beginRemoveRows ( parent, row, row+count ); for (int i = 0; iremoveChildContainer(row); } endRemoveRows(); return true; } */ diff --git a/src/collection/containermodel.h b/src/collection/containermodel.h index 89aaf3bd..a7e5df69 100644 --- a/src/collection/containermodel.h +++ b/src/collection/containermodel.h @@ -1,82 +1,81 @@ /*************************************************************************** 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 CONTAINERMODEL_H #define CONTAINERMODEL_H -#include "readonlycontainermodel.h" - #include #include #include #include #include +#include /** * Model for the tree of containers (lessons, word types). */ -class ContainerModel : public ReadonlyContainerModel +class ContainerModel : public KEduVocReadonlyContainerModel { Q_OBJECT public: enum ColumnType { ContainerNameColumn = 0, TotalCountColumn, FirstDataColumn }; explicit ContainerModel(KEduVocContainer::EnumContainerType type, QObject *parent = 0); QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE; QStringList mimeTypes() const Q_DECL_OVERRIDE; QMimeData * mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) Q_DECL_OVERRIDE; /** Change the name or checkbox of a lesson. * @param index which lesson * @param value new name * @param role * @return bool @c true it worked */ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; QModelIndex appendContainer(const QModelIndex& parent, const QString & containerName = QString()); void deleteContainer(const QModelIndex& containerIndex); /** Indicate supported drag actions @return enum of actions supported **/ Qt::DropActions supportedDragActions() const Q_DECL_OVERRIDE; signals: /** * emitted when the inPractice state or name of a lesson changed. */ void documentModified(); }; #endif diff --git a/src/collection/lessonmodel.cpp b/src/collection/lessonmodel.cpp index 6ea858b7..68d77686 100644 --- a/src/collection/lessonmodel.cpp +++ b/src/collection/lessonmodel.cpp @@ -1,117 +1,117 @@ /*************************************************************************** Copyright 2008-2009 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 "lessonmodel.h" #include "parleydocument.h" #include #include #include /** @file * Implementation of LessonModel. * Functions to create the model from the lessons of the vocabulary document. */ LessonModel::LessonModel(QObject * parent) : ContainerModel(KEduVocContainer::Lesson, parent) { } KEduVocContainer * LessonModel::rootContainer() const { - if (!m_doc) { + if (!document()) { return 0; } - return m_doc->lesson(); + return document()->lesson(); } Qt::ItemFlags LessonModel::flags(const QModelIndex &index) const { if (index.isValid() && index.parent() == QModelIndex()) { return (Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable); } // the name column should be checkable to select lessons for practice return ContainerModel::flags(index); } QVariant LessonModel::data(const QModelIndex & index, int role) const { if (index.isValid() && !index.parent().isValid()) { if (index.column() == 0) { switch (role) { case Qt::DisplayRole: return i18nc("display of the name of the vocabulary collection", "Collection: %1", ContainerModel::data(index, role).toString()); case Qt::FontRole: QFont f; f.setBold(true); return f; } } } return ContainerModel::data(index, role); } bool LessonModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && !index.parent().isValid()) { if (index.column() == ContainerNameColumn && role == Qt::EditRole) { ///@todo decouple the root lesson and document title - m_doc->setTitle(value.toString()); + document()->setTitle(value.toString()); } } return ContainerModel::setData(index, value, role); } void LessonModel::splitLesson(const QModelIndex& containerIndex, int entriesPerLesson, SplitLessonOrder order) { if (!containerIndex.isValid()) { return; } if (static_cast(containerIndex.internalPointer())->containerType() != KEduVocContainer::Lesson) { return; } KEduVocLesson* parentLesson = static_cast(containerIndex.internalPointer()); int numNewLessons = parentLesson->entryCount() / entriesPerLesson; // modulo - fraction lesson if not 0 we need one more if (parentLesson->entryCount() % entriesPerLesson) { numNewLessons++; } while (parentLesson->entryCount() > 0) { beginInsertRows(containerIndex, parentLesson->entryCount(), parentLesson->entryCount()); KEduVocLesson* child = new KEduVocLesson(parentLesson->name() + QStringLiteral(" %1").arg(parentLesson->childContainerCount() + 1), parentLesson); parentLesson->appendChildContainer(child); endInsertRows(); while (parentLesson->entryCount() > 0 && child->entryCount() < entriesPerLesson) { // next entry to be assigned to one of the new lessons int nextEntry = 0; if (order == Random) { nextEntry = KRandom::random() % parentLesson->entryCount(); child->appendEntry(parentLesson->entry(nextEntry)); } } } } diff --git a/src/collection/wordclassmodel.cpp b/src/collection/wordclassmodel.cpp index 565f818e..6f5eb29f 100644 --- a/src/collection/wordclassmodel.cpp +++ b/src/collection/wordclassmodel.cpp @@ -1,34 +1,34 @@ /*************************************************************************** Copyright 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. * * * ***************************************************************************/ // Own #include "wordclassmodel.h" #include WordClassModel::WordClassModel(QObject * parent) : ContainerModel(KEduVocContainer::WordType, parent) { } KEduVocContainer * WordClassModel::rootContainer() const { - if (!m_doc) { + if (!document()) { return 0; } - return m_doc->wordTypeContainer(); + return document()->wordTypeContainer(); } diff --git a/src/editor/vocabularydelegate.cpp b/src/editor/vocabularydelegate.cpp index fd8f40d3..3e537fdf 100644 --- a/src/editor/vocabularydelegate.cpp +++ b/src/editor/vocabularydelegate.cpp @@ -1,372 +1,373 @@ /*************************************************************************** Copyright 2006, 2007 Peter Hedlund 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 "vocabularydelegate.h" #include "vocabularyfilter.h" #include "prefs.h" #include "languagesettings.h" -#include "readonlycontainermodel.h" #include #include #include +#include + #include #include #include #include #include #include #include #include #include #include using namespace Editor; VocabularyDelegate::VocabularyDelegate(QObject *parent) : QItemDelegate(parent), m_doc(0), m_translator(0) { } QSet VocabularyDelegate::getTranslations(const QModelIndex & index) const { if (Prefs::automaticTranslation() == false) return QSet(); QSet translations; //translations of this column from all the other languages int language = index.column() / KEduVocVocabularyModel::EntryColumnsMAX; QString toLanguage = m_doc->identifier(language).locale(); //iterate through all the Translation columns for (int i = 0; i < index.model()->columnCount(index.parent()); i ++) { if (KEduVocVocabularyModel::columnType(i) == KEduVocVocabularyModel::Translation) { //translation column QString fromLanguage = m_doc->identifier(KEduVocVocabularyModel::translation(i)).locale(); QString word = index.model()->index(index.row(), i, QModelIndex()).data().toString(); if (fromLanguage != toLanguage) { // qDebug() << fromLanguage << toLanguage << word; //get the word translations and add them to the translations set QSet * tr = m_translator->getTranslation(word, fromLanguage, toLanguage); if (tr) translations.unite(* (tr)); } } } return translations; } QWidget * VocabularyDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { Q_UNUSED(option); /// as long as it's unused if (!index.isValid()) { return 0; } switch (KEduVocVocabularyModel::columnType(index.column())) { case KEduVocVocabularyModel::WordClass: { if (!m_doc) return 0; KComboBox *wordTypeCombo = new KComboBox(parent); WordTypeBasicModel *basicWordTypeModel = new WordTypeBasicModel(parent); wordTypeCombo->setModel(basicWordTypeModel); QTreeView *view = new QTreeView(parent); view->setModel(basicWordTypeModel); wordTypeCombo->setView(view); view->header()->setVisible(false); view->setRootIsDecorated(true); basicWordTypeModel->setDocument(m_doc); view->expandAll(); qDebug() << "index data" << index.data().toString(); //view->setCurrentItem(); return wordTypeCombo; } case KEduVocVocabularyModel::Translation: { if (!m_doc || !m_translator) return 0; if (KEduVocVocabularyModel::columnType(index.column()) == KEduVocVocabularyModel::Translation) { //get the translations of this word (fetch only with the help of scripts, if enabled) QSet translations = getTranslations(index); //create combo box //if there is only one word and that is the suggestion word (in translations) then don't create the combobox if (!translations.isEmpty() && !(translations.size() == 1 && (*translations.begin()) == index.model()->data(index, Qt::DisplayRole).toString())) { KComboBox *translationCombo = new KComboBox(parent); translationCombo->setFrame(false); translationCombo->addItems(translations.toList()); translationCombo->setEditable(true); translationCombo->setFont(index.model()->data(index, Qt::FontRole).value()); translationCombo->setEditText(index.model()->data(index, Qt::DisplayRole).toString()); translationCombo->completionObject()->setItems(translations.toList()); return translationCombo; } } // no break - we fall back to a line edit if there are not multiple translations fetched onlin // fallthrough default: { QLineEdit *editor = new QLineEdit(parent); editor->setFrame(false); editor->setFont(index.model()->data(index, Qt::FontRole).value()); editor->setText(index.model()->data(index, Qt::DisplayRole).toString()); QString locale = index.model()->data(index, KEduVocVocabularyModel::LocaleRole).toString(); if (!locale.isEmpty()) { LanguageSettings settings(locale); settings.load(); QString layout = settings.keyboardLayout(); if (!layout.isEmpty()) { QDBusInterface kxkb(QStringLiteral("org.kde.keyboard"), QStringLiteral("/Layouts"), QStringLiteral("org.kde.KeyboardLayouts")); if (kxkb.isValid()) { kxkb.call(QStringLiteral("setLayout"), layout); } } } return editor; } } } bool VocabularyDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { Q_UNUSED(view); if (event->type() == QEvent::ToolTip) { QPainterPath audioPainterPath; QPainterPath imagePainterPath; audioPainterPath.addPolygon(audioPolygon(option)); imagePainterPath.addPolygon(imagePolygon(option)); int column = columnType(index.column()); if (audioPainterPath.contains(event->pos()) && hasAudio(index) && (column == Translation || column == Pronunciation)) { QToolTip::showText(event->globalPos(), i18n("Sound file selected: %1", audioUrl(index))); } else if (imagePainterPath.contains(event->pos()) && hasImage(index) && (column == Translation || column == Pronunciation)) { QToolTip::showText(event->globalPos(), i18n("Image file selected: %1", imageUrl(index))); } else { QToolTip::hideText(); event->ignore(); } return true; } return false; } QPolygon VocabularyDelegate::audioPolygon(const QStyleOptionViewItem &option) const { QRect rect = option.rect; QPolygon polygon; polygon << QPoint(rect.x() + rect.width() - 10, rect.y()); polygon << QPoint(rect.x() + rect.width(), rect.y()); polygon << QPoint(rect.x() + rect.width(), rect.y() + 10); return polygon; } QPolygon VocabularyDelegate::imagePolygon(const QStyleOptionViewItem &option) const { QRect rect = option.rect; QPolygon polygon; polygon << QPoint(rect.x() + rect.width() - 10, rect.y() + rect.height()); polygon << QPoint(rect.x() + rect.width(), rect.y() + rect.height()); polygon << QPoint(rect.x() + rect.width(), rect.y() + rect.height() - 10); return polygon; } bool VocabularyDelegate::hasAudio(const QModelIndex &index) const { return !audioUrl(index).isEmpty(); } bool VocabularyDelegate::hasImage(const QModelIndex &index) const { return !imageUrl(index).isEmpty(); } QString VocabularyDelegate::audioUrl(const QModelIndex &index) const { QVariant audioVar = index.data(KEduVocVocabularyModel::AudioRole); QString audioUrl = audioVar.toString(); return audioUrl; } QString VocabularyDelegate::imageUrl(const QModelIndex &index) const { QVariant imageVar = index.data(KEduVocVocabularyModel::ImageRole); QString imageUrl = imageVar.toString(); return imageUrl; } int VocabularyDelegate::columnType(int column) { return column % EntryColumnsMAX; } void VocabularyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QItemDelegate::paint(painter, option, index); painter->save(); int column = columnType(index.column()); if (hasAudio(index) == true && (column == Translation || column == Pronunciation)) { painter->setPen(QPen(Qt::red)); painter->setBrush(QBrush(Qt::red)); painter->drawPolygon(audioPolygon(option)); } if (hasImage(index) == true && (column == Translation || column == Pronunciation)) { painter->setPen(QPen(Qt::blue)); painter->setBrush(QBrush(Qt::blue)); painter->drawPolygon(imagePolygon(option)); } painter->restore(); } void VocabularyDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const { if (!index.isValid()) { return; } switch (KEduVocVocabularyModel::columnType(index.column())) { case (KEduVocVocabularyModel::Translation) : { QString value = index.model()->data(index, Qt::DisplayRole).toString(); KComboBox * translationCombo = qobject_cast (editor); if (translationCombo) { translationCombo->setEditText(value); if (value.isEmpty()) { // show the translations that were fetched as popup translationCombo->showPopup(); } break; } } // fallthrough default: { QString value = index.model()->data(index, Qt::DisplayRole).toString(); QLineEdit *lineEdit = qobject_cast (editor); if (lineEdit) { lineEdit->setText(value); } } } } void VocabularyDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const { if (!index.isValid()) { return; } switch (KEduVocVocabularyModel::columnType(index.column())) { case (KEduVocVocabularyModel::WordClass) : { qDebug() << "word type editor"; KComboBox *combo = qobject_cast (editor); if (!combo) { return; } qDebug() << "combo" << combo->currentText(); QModelIndex comboIndex = combo->view()->currentIndex(); KEduVocWordType* wordType = static_cast(comboIndex.internalPointer()); // the root is the same as no word type if (wordType && wordType->parent() == 0) { wordType = 0; } VocabularyFilter *filter = qobject_cast (model); KEduVocVocabularyModel *vocModel = qobject_cast ((filter)->sourceModel()); Q_ASSERT(vocModel); QVariant data = vocModel->data(filter->mapToSource(index), KEduVocVocabularyModel::EntryRole); KEduVocExpression *expression = data.value(); Q_ASSERT(expression); int translationId = KEduVocVocabularyModel::translation(index.column()); expression->translation(translationId)->setWordType(wordType); model->setData(index, combo->currentText()); break; } case (KEduVocVocabularyModel::Translation) : { QLineEdit *lineEdit = qobject_cast (editor); if (lineEdit) { model->setData(index, lineEdit->text()); } break; } default: { QLineEdit *lineEdit = qobject_cast (editor); if (lineEdit) { model->setData(index, lineEdit->text()); } } } } void VocabularyDelegate::setDocument(KEduVocDocument * doc) { m_doc = doc; } /* QPair< QString, QString > VocabularyDelegate::guessWordType(const QString & entry, int language) const { qDebug() << "guessing word type for: " << entry; QString article = entry.section(" ", 0, 0); if ( article.length() < entry.length() ) { if ( article == ->identifier(language).articles().article(KEduVocWordFlag::Singular| KEduVocWordFlag::Definite| KEduVocWordFlag::Masculine) ) { qDebug() << "Noun masculine"; return qMakePair(m_doc->wordTypes().specialTypeNoun(), m_doc->wordTypes().specialTypeNounMale()); } } return qMakePair(QString(), QString()); } */ VocabularyDelegate::WordTypeBasicModel::WordTypeBasicModel(QObject * parent) - : ReadonlyContainerModel(KEduVocContainer::WordType, parent) + : KEduVocReadonlyContainerModel(KEduVocContainer::WordType, parent) { } KEduVocContainer * VocabularyDelegate::WordTypeBasicModel::rootContainer() const { - if (!m_doc) { + if (!document()) { return 0; } - return m_doc->wordTypeContainer(); + return document()->wordTypeContainer(); } /** * Sets the member variable m_translator to a Translator object * @param translator Translator Object to be used for retrieving word translations */ void VocabularyDelegate::setTranslator(Translator* translator) { m_translator = translator; } diff --git a/src/editor/vocabularydelegate.h b/src/editor/vocabularydelegate.h index b986db30..c3622ffd 100644 --- a/src/editor/vocabularydelegate.h +++ b/src/editor/vocabularydelegate.h @@ -1,92 +1,93 @@ /*************************************************************************** Copyright 2006, 2007 Peter Hedlund 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. * * * ***************************************************************************/ #ifndef VOCABULARYDELEGATE_H #define VOCABULARYDELEGATE_H -#include "readonlycontainermodel.h" #include "../scripts/translator.h" #include #include +#include + class KEduVocDocument; namespace Editor { class VocabularyDelegate : public QItemDelegate { Q_OBJECT public: enum entryColumns { Translation = 0, Pronunciation, WordType, Synonym, Antonym, Example, Comment, Paraphrase, // Audio, // Image, EntryColumnsMAX }; explicit VocabularyDelegate(QObject *parent = 0); QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE; void setTranslator(Translator * translator); static int columnType(int column); bool hasAudio(const QModelIndex &index) const; bool hasImage(const QModelIndex &index) const; QString audioUrl(const QModelIndex &index) const; QString imageUrl(const QModelIndex &index) const; QPolygon audioPolygon(const QStyleOptionViewItem &option) const; QPolygon imagePolygon(const QStyleOptionViewItem &option) const; public slots: void setDocument(KEduVocDocument *doc); bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index ) Q_DECL_OVERRIDE; private: KEduVocDocument *m_doc; Translator * m_translator; /** Returns the translations of the word of the given index */ QSet getTranslations(const QModelIndex & index) const; // for the word type combo class WordTypeBasicModel; }; -class VocabularyDelegate::WordTypeBasicModel : public ReadonlyContainerModel +class VocabularyDelegate::WordTypeBasicModel : public KEduVocReadonlyContainerModel { public: explicit WordTypeBasicModel(QObject *parent = 0); protected: KEduVocContainer * rootContainer() const Q_DECL_OVERRIDE; }; } #endif diff --git a/src/statistics/statisticsmodel.cpp b/src/statistics/statisticsmodel.cpp index 1e9331bb..c2d791b4 100644 --- a/src/statistics/statisticsmodel.cpp +++ b/src/statistics/statisticsmodel.cpp @@ -1,207 +1,207 @@ /*************************************************************************** Copyright 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 "statisticsmodel.h" #include "statisticslegendwidget.h" #include "utils.h" #include #include #include #include #include #include StatisticsModel::StatisticsModel(QObject *parent) : ContainerModel(KEduVocContainer::Lesson, parent) { } QVariant StatisticsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (section >= FirstDataColumn) { if (role == Qt::DisplayRole - && m_doc->identifierCount() > (section - FirstDataColumn) ) { + && document()->identifierCount() > (section - FirstDataColumn) ) { return i18nc("Confidence level in language, table header", "Confidence (%1)" - , m_doc->identifier(section - FirstDataColumn).name()); + , document()->identifier(section - FirstDataColumn).name()); } } return ContainerModel::headerData(section, orientation, role); } QVariant StatisticsModel::data(const QModelIndex &index, int role) const { Q_ASSERT(!m_documentSettings.isEmpty()); KEduVocContainer *container = static_cast(index.internalPointer()); // Entrie count if (index.column() == TotalCountColumn) { if (role == Qt::DisplayRole) { switch (Prefs::practiceDirection()) { case Prefs::EnumPracticeDirection::KnownToLearning: return entryCountForPracticeMode(container, Prefs::learningLanguage()); case Prefs::EnumPracticeDirection::LearningToKnown: return entryCountForPracticeMode(container, Prefs::knownLanguage()); case Prefs::EnumPracticeDirection::MixedDirectionsWordsOnly: case Prefs::EnumPracticeDirection::MixedDirectionsWithSound: return entryCountForPracticeMode(container, Prefs::knownLanguage()) + entryCountForPracticeMode(container, Prefs::learningLanguage()); default: return entryCountForPracticeMode(container, Prefs::learningLanguage()); } } if (role == Qt::TextAlignmentRole) { return Qt::AlignRight; } } // Colorbars if (index.column() >= FirstDataColumn) { int translation = index.column() - FirstDataColumn; switch (role) { case Container: { // Return a pointer to the container we are working on. QVariant var; var.setValue(container); return var; } case TotalPercent: // Average grade return averageGradeForPracticeMode(container, translation); case TotalCount: return entryCountForPracticeMode(container, translation); case ActiveConjugationTenses: return m_documentSettings.at(translation)->conjugationTenses(); default: if ((role >= Grade0) && (role <= Grade7)) { return expressionsOfGradeForPracticeMode(container, translation, role - Grade0); } } } // Checkboxes if (index.column() == 0 && role == Qt::CheckStateRole) { if (container->inPractice()) { return Qt::Checked; } else { return Qt::Unchecked; } } return ContainerModel::data(index, role); } int StatisticsModel::averageGradeForPracticeMode(KEduVocContainer *container, int translation) const { WordCount wordCount; wordCount.fillFromContainerForPracticeMode( *container, translation, m_documentSettings.at(translation)->conjugationTenses() ); return wordCount.percentageCompleted(); } int StatisticsModel::entryCountForPracticeMode(KEduVocContainer *container, int translation) const { WordCount wordCount; wordCount.fillFromContainerForPracticeMode( *container, translation, m_documentSettings.at(translation)->conjugationTenses() ); return wordCount.totalWords - wordCount.invalid; } int StatisticsModel::expressionsOfGradeForPracticeMode(KEduVocContainer *container, int translation, grade_t grade) const { WordCount wordCount; wordCount.fillFromContainerForPracticeMode( *container, translation, m_documentSettings.at(translation)->conjugationTenses() ); return wordCount.grades[grade]; } Qt::ItemFlags StatisticsModel::flags(const QModelIndex &index) const { if (index.isValid()) { if (index.column() == 0) { return (Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable); } return (Qt::ItemIsEnabled | Qt::ItemIsSelectable); } return 0; } int StatisticsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) - return m_doc->identifierCount() + FirstDataColumn; + return document()->identifierCount() + FirstDataColumn; } Qt::DropActions StatisticsModel::supportedDragActions() const { return 0; } KEduVocContainer *StatisticsModel::rootContainer() const { - if (!m_doc) { + if (!document()) { return 0; } - return m_doc->lesson(); + return document()->lesson(); } void StatisticsModel::loadDocumentsSettings() { m_documentSettings.clear(); if (m_doc == nullptr) { return; } for (int i = 0 ; i < m_doc->identifierCount(); ++i) { m_documentSettings << QSharedPointer( new DocumentSettings(m_doc->url().url() + QString::number(i)) ); m_documentSettings.last()->load(); } } void StatisticsModel::setDocument(KEduVocDocument *doc) { beginResetModel(); m_doc = doc; loadDocumentsSettings(); endResetModel(); } void StatisticsModel::updateDocumentSettings() { beginResetModel(); loadDocumentsSettings(); endResetModel(); } const KEduVocDocument *StatisticsModel::document() const { return m_doc; }