Commit e1d2df5e authored by Andreas Cord-Landwehr's avatar Andreas Cord-Landwehr
Browse files

Create abstract item model for units & phrases.

parent ef6afbee
......@@ -40,7 +40,7 @@ include(ECMSetupVersion)
include(FeatureSummary)
include(GenerateExportHeader)
find_package(Qt5 REQUIRED COMPONENTS
find_package(Qt5 5.5 REQUIRED COMPONENTS
Widgets
Sql
XmlPatterns
......
......@@ -98,6 +98,7 @@ set(artikulate_SRCS
models/learningprogressmodel.cpp
models/unitmodel.cpp
models/unitfiltermodel.cpp
models/phrasemodel.cpp
models/phraselistmodel.cpp
models/phrasefiltermodel.cpp
models/phonememodel.cpp
......@@ -129,6 +130,7 @@ set(artikulate_editor_SRCS
models/learningprogressmodel.cpp
models/unitmodel.cpp
models/unitfiltermodel.cpp
models/phrasemodel.cpp
models/phraselistmodel.cpp
models/phrasefiltermodel.cpp
models/phonememodel.cpp
......
......@@ -39,6 +39,7 @@
#include "models/learningprogressmodel.h"
#include "models/unitmodel.h"
#include "models/unitfiltermodel.h"
#include "models/phrasemodel.h"
#include "models/phraselistmodel.h"
#include "models/phrasefiltermodel.h"
#include "models/phonememodel.h"
......@@ -90,6 +91,7 @@ void Application::registerQmlTypes()
qmlRegisterType<LearningProgressModel>("artikulate", 1, 0, "LearningProgressModel");
qmlRegisterType<UnitModel>("artikulate", 1, 0, "UnitModel");
qmlRegisterType<UnitFilterModel>("artikulate", 1, 0, "UnitFilterModel");
qmlRegisterType<PhraseModel>("artikulate", 1, 0, "PhraseModel");
qmlRegisterType<PhraseListModel>("artikulate", 1, 0, "PhraseListModel");
qmlRegisterType<PhraseFilterModel>("artikulate", 1, 0, "PhraseFilterModel");
qmlRegisterType<PhonemeModel>("artikulate", 1, 0, "PhonemeModel");
......
......@@ -24,13 +24,14 @@
#include "core/unit.h"
#include "core/phrase.h"
#include "core/phonemegroup.h"
#include <QDebug>
EditorSession::EditorSession(QObject *parent)
: QObject(parent)
, m_language(0)
, m_course(0)
, m_unit(0)
, m_phonemeGroup(0)
, m_language(nullptr)
, m_course(nullptr)
, m_unit(nullptr)
, m_phonemeGroup(nullptr)
, m_type(Phrase::Word)
{
......@@ -46,8 +47,8 @@ void EditorSession::setLanguage(Language *language)
if (m_language == language) {
return;
}
setCourse(0);
setUnit(0);
setCourse(nullptr);
setUnit(nullptr);
m_language = language;
emit languageChanged();
}
......@@ -62,7 +63,7 @@ void EditorSession::setCourse(Course *course)
if (m_course == course) {
return;
}
setUnit(0);
setUnit(nullptr);
m_course = course;
emit courseChanged();
}
......
......@@ -70,7 +70,7 @@ void LanguageModel::setResourceModel(LanguageResourceModel *resourceModel)
}
}
bool LanguageModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
bool LanguageModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
return QSortFilterProxyModel::lessThan(left, right);
}
......
/*
* Copyright 2013-2015 Andreas Cord-Landwehr <cordlandwehr@kde.org>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "phrasemodel.h"
#include "core/course.h"
#include "core/unit.h"
#include "core/phrase.h"
#include <QAbstractItemModel>
#include <QSignalMapper>
#include <KLocalizedString>
#include <QDebug>
PhraseModel::PhraseModel(QObject *parent)
: QAbstractItemModel(parent)
, m_course(nullptr)
{
}
QHash< int, QByteArray > PhraseModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[TextRole] = "text";
roles[DataRole] = "dataRole";
return roles;
}
void PhraseModel::setCourse(Course *course)
{
if (m_course == course) {
return;
}
beginResetModel();
if (m_course) {
m_course->disconnect(this);
foreach (auto unit, m_course->unitList()) {
unit->disconnect();
foreach (auto phrase, unit->phraseList()) {
phrase->disconnect();
}
}
}
m_course = course;
if (m_course) {
// initial setting of signal mappings
foreach (auto unit, m_course->unitList()) {
connect(unit, &Unit::phraseAboutToBeAdded, this, &PhraseModel::onPhraseAboutToBeAdded);
connect(unit, static_cast<void (Unit::*)()>(&Unit::phraseAdded), this, &PhraseModel::onPhraseAdded);
connect(unit, &Unit::phraseAboutToBeRemoved, this, &PhraseModel::onPhrasesAboutToBeRemoved);
connect(unit, static_cast<void (Unit::*)()>(&Unit::phraseRemoved), this, &PhraseModel::onPhrasesRemoved);
//TODO connect to unit changes, not needed currently, though
// insert and connect all already existing phrases
int phrases = unit->phraseList().count();
for (int i = 0; i < phrases; ++i) {
onPhraseAboutToBeAdded(unit->phraseList().at(i), i);
endInsertRows();
}
}
}
// emit done
endResetModel();
emit courseChanged();
}
Course * PhraseModel::course() const
{
return m_course;
}
QVariant PhraseModel::data(const QModelIndex &index, int role) const
{
Q_ASSERT(m_course);
if (!index.isValid()) {
return QVariant();
}
if (!index.internalPointer()) {
Unit *unit = m_course->unitList().at(index.row());
switch(role)
{
case TextRole:
return unit->title();
case DataRole:
return QVariant::fromValue<QObject*>(unit);
default:
return QVariant();
}
}
else {
Unit *unit = static_cast<Unit*>(index.internalPointer());
switch(role)
{
case TextRole:
return unit->phraseList().at(index.row())->text();
case DataRole:
return QVariant::fromValue<QObject*>(unit->phraseList().at(index.row()));
default:
return QVariant();
}
}
return QVariant();
}
int PhraseModel::rowCount(const QModelIndex &parent) const
{
if (!m_course) {
return 0;
}
// no valid index -> must be (invisible) root
if (!parent.isValid()) {
return m_course->unitList().count();
}
// internal pointer -> must be a phrase
if (parent.internalPointer()) {
return 0;
}
// else -> must be a unit
Unit *unit = m_course->unitList().at(parent.row());
return unit->phraseList().count();
}
int PhraseModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 1;
}
QModelIndex PhraseModel::parent(const QModelIndex &child) const
{
if (!child.internalPointer()) {
return QModelIndex();
}
Unit *parent = static_cast<Unit*>(child.internalPointer());
for (int i = 0; i < m_course->unitList().count(); ++i) {
if (m_course->unitList().at(i) == parent) {
return createIndex(i, 0);
}
}
return QModelIndex();
}
QModelIndex PhraseModel::index(int row, int column, const QModelIndex &parent) const
{
if (!parent.isValid()) { // unit elements
return createIndex(row, column);
} else { // phrase elements
Unit *unit = m_course->unitList().at(parent.row());
if (unit) {
return createIndex(row, column, unit);
}
}
return QModelIndex();
}
void PhraseModel::onPhraseAboutToBeAdded(Phrase *phrase, int index)
{
int unitIndex = m_course->unitList().indexOf(phrase->unit());
beginInsertRows(createIndex(unitIndex, 0), index, index);
}
void PhraseModel::onPhraseAdded()
{
endInsertRows();
}
void PhraseModel::onPhrasesAboutToBeRemoved(int first, int last)
{
//TODO better solution requires access to unit
beginResetModel();
}
void PhraseModel::onPhrasesRemoved()
{
endResetModel();
}
QVariant PhraseModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole) {
return QVariant();
}
if (orientation == Qt::Vertical) {
return QVariant(section + 1);
}
return QVariant(i18nc("@title:column", "Phrase"));
}
/*
* Copyright 2013-2015 Andreas Cord-Landwehr <cordlandwehr@kde.org>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHRASEMODEL_H
#define PHRASEMODEL_H
#include <QAbstractItemModel>
#include "core/phrase.h"
class Course;
class QSignalMapper;
class PhraseModel : public QAbstractItemModel
{
Q_OBJECT
Q_PROPERTY(Course *course READ course WRITE setCourse NOTIFY courseChanged)
public:
enum phraseRoles {
TextRole = Qt::UserRole + 1,
IdRole,
TypeRole,
SoundFileRole,
ExcludedRole,
DataRole
};
explicit PhraseModel(QObject *parent = nullptr);
virtual QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE;
void setCourse(Course *course);
Course * course() const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
virtual QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE;
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const Q_DECL_OVERRIDE;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
Q_SIGNALS:
void phraseChanged(int index);
void courseChanged();
void typeChanged();
private Q_SLOTS:
void onPhraseAboutToBeAdded(Phrase *phrase, int index);
void onPhraseAdded();
void onPhrasesAboutToBeRemoved(int first, int last);
void onPhrasesRemoved();
private:
Course *m_course;
};
#endif
......@@ -19,7 +19,7 @@
*/
import QtQuick 2.1
import QtQuick.Controls 1.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2
import org.kde.kquickcontrolsaddons 2.0
import artikulate 1.0
......@@ -76,6 +76,7 @@ Item
}
RowLayout {
id: languageRow
Label {
text: i18n("Language")
}
......@@ -99,20 +100,56 @@ Item
}
}
RowLayout {
id: courseRow
Label {
text: i18n("Course")
}
ComboBox {
id: combo
Layout.minimumWidth: 200
Layout.fillWidth: true
model: CourseModel {
id: courseModel
resourceManager: g_resourceManager
language: editorSession.language
onLanguageChanged: {
if (courseModel.course(0)) {
editorSession.course = courseModel.course(0)
}
}
}
textRole: "title"
onCurrentIndexChanged: {
editorSession.course = courseModel.course(currentIndex)
if (courseModel.course(currentIndex)) {
editorSession.course = courseModel.course(currentIndex)
}
}
}
}
RowLayout {
id: mainRow
height: main.height - languageRow.height - courseRow.height - 2 * 15
ScrollView {
Layout.minimumWidth: Math.floor(main.width * 0.3)
Layout.fillHeight: true
TreeView {
height: mainRow.height
width: Math.floor(main.width * 0.3) - 20
TableViewColumn {
title: i18n("Units & Phrases")
role: "text"
}
model: PhraseModel {
course: editorSession.course
}
itemDelegate: Item {
Text {
anchors.verticalCenter: parent.verticalCenter
color: styleData.textColor
elide: styleData.elideMode
text: styleData.value
}
}
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment