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

Again implement changing of learner profile image.

parent d6728382
/*
* Copyright 2013-2014 Andreas Cord-Landwehr <cordlandwehr@kde.org>
* Copyright 2013-2016 Andreas Cord-Landwehr <cordlandwehr@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -21,6 +21,7 @@
#include "learner.h"
#include "learner_p.h"
#include "learninggoal.h"
#include <QDir>
#include <QHash>
#include <QFileInfo>
#include <QPixmap>
......@@ -71,11 +72,24 @@ void Learner::setIdentifier(int identifier)
QString Learner::imageUrl() const
{
QString path = d->imageUrl();
QString path = d->imagePath();
if (!QFileInfo(path).exists()) {
return QString();
}
return path;
return "file://" + path;
}
void Learner::clearImage()
{
const QString path {d->imagePath()};
if (!QFileInfo(path).exists()) {
return;
}
QFile file;
if (!file.remove(path)) {
qCCritical(LIBLEARNER_LOG) << "could not remove image:" << path;
}
emit imageChanged();
}
void Learner::importImage(const QString &path)
......@@ -84,11 +98,20 @@ void Learner::importImage(const QString &path)
qCWarning(LIBLEARNER_LOG) << "image path points to a non-existing file, aborting: " << path;
return;
}
// create image directory if it does not exist
QDir dir;
if (!dir.exists(d->imageDirectory())) {
dir.mkdir(d->imageDirectory());
}
QPixmap image = QPixmap(path);
image = image.scaled(120, 120);
image.save(d->imageUrl());
emit imageUrlChanged();
qCDebug(LIBLEARNER_LOG) << "saved scaled image from " << path << " at " << d->imageUrl();
if (!image.save(d->imagePath(), "PNG")) {
qCCritical(LIBLEARNER_LOG()) << "could not save scaled image to" << d->imagePath();
}
emit imageChanged();
qCDebug(LIBLEARNER_LOG) << "saved scaled image from " << path << " at " << d->imagePath();
}
QList< LearningGoal* > Learner::goals() const
......
......@@ -38,7 +38,7 @@ class LIBLEARNERPROFILE_EXPORT Learner : public QObject
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(int id READ identifier WRITE setIdentifier NOTIFY identifierChanged)
Q_PROPERTY(QString imageUrl READ imageUrl NOTIFY imageUrlChanged)
Q_PROPERTY(QString imageUrl READ imageUrl NOTIFY imageChanged)
Q_PROPERTY(QList<LearnerProfile::LearningGoal*> goals READ goals NOTIFY goalCountChanged)
public:
......@@ -57,7 +57,12 @@ public:
QString name() const;
void setName(const QString &name);
/**
* \return URL to image
* \note since it is a local file the path begins with "file://"
*/
QString imageUrl() const;
Q_INVOKABLE void clearImage();
void importImage(const QString &path);
int identifier() const;
void setIdentifier(int identifier);
......@@ -71,7 +76,7 @@ public:
Q_SIGNALS:
void nameChanged();
void imageUrlChanged();
void imageChanged();
void identifierChanged();
void goalAboutToBeAdded(LearningGoal*,int);
void goalAdded();
......
......@@ -26,6 +26,7 @@
#include <QHash>
#include <QStandardPaths>
#include "learninggoal.h"
#include <QDebug>
namespace LearnerProfile
{
......@@ -41,10 +42,17 @@ public:
}
~LearnerPrivate() {}
QString imageUrl() const
QString imagePath() const
{
QString relPath = QString("images/learner%1.png").arg(m_identifier);
return QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + relPath;
const QString name = QString("learner%1.png").arg(m_identifier);
return imageDirectory() + name;
}
QString imageDirectory() const
{
return QStandardPaths::writableLocation(QStandardPaths::DataLocation)
+ QLatin1Char('/')
+ QString("images")
+ QLatin1Char('/');
}
QString m_name;
......
......@@ -157,11 +157,11 @@ int ProfileManager::profileCount() const
void ProfileManager::openImageFileDialog()
{
QString imageUrl = QFileDialog::getOpenFileName(0,
const QString imagePath = QFileDialog::getOpenFileName(0,
i18n("Open Image"),
"",
i18n("Image Files (*.png *.jpg *.bmp)"));
d->m_activeProfile->importImage(imageUrl);
d->m_activeProfile->importImage(imagePath);
}
Learner * ProfileManager::addProfile(const QString &name)
......
......@@ -175,13 +175,9 @@ ApplicationWindow {
anchors {
fill: main
}
content: Item {}
// content: ProfileSelector {
// anchors.fill: parent
// onProfileChosen: {
// profileSelectorSheet.close()
// }
// }
content: ProfileSettingsItem {
anchors.fill: parent
}
}
}
/*
* Copyright 2016 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/>.
*/
import QtQuick 2.1
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.2
import artikulate 1.0
Item {
id: root
ColumnLayout {
id: main
anchors.fill: parent
Label {
text: i18n("User Profile Settings")
font.pointSize: 1.5 * theme.fontPointSize
}
ProfileUserItem {
profile: g_profileManager.activeProfile
}
}
}
\ No newline at end of file
/*
* Copyright 2016 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/>.
*/
import QtQuick 2.1
import QtQuick.Controls 1.2
import org.kde.kquickcontrolsaddons 2.0
import artikulate 1.0
Item {
id: root
height: 120
width: height
property Learner profile: null
Component {
id: profileImage
Image {
Connections {
target: profile
onImageUrlChanged: {
// trigger reload
source = ""
source = profile.imageUrl
}
}
anchors.fill: parent
fillMode: Image.Pad
cache: false
source: profile.imageUrl
}
}
Component {
id: dummyImage
QIconItem {
anchors.fill: parent
icon: "user-identity"
}
}
Loader {
anchors.fill: parent
sourceComponent: profile.imageUrl == "" ? dummyImage : profileImage
}
}
/*
* Copyright 2012 Sebastian Gottfried <sebastiangottfried@web.de>
* Copyright 2013-2014 Andreas Cord-Landwehr <cordlandwehr@kde.org>
* Copyright 2013-2016 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
......@@ -21,6 +21,7 @@
import QtQuick 2.1
import QtQuick.Controls 1.2
import org.kde.kquickcontrolsaddons 2.0
import artikulate 1.0
Item {
......@@ -43,31 +44,17 @@ Item {
onProfileChanged: update()
Image {
ProfileUserImageItem {
id: imageLearner
width: 120
height: 120
width: height
profile: root.profile
anchors {
top: root.top
right: root.right
topMargin: 30
leftMargin: 30
}
fillMode: Image.Pad
cache: false
source: profile.imageUrl ? profile.imageUrl : "../images/user-identity.png"
Connections {
target: profile
onImageUrlChanged: {
imageLearner.source = "" // trigger reload
if (profile.imageUrl) {
imageLearner.source = profile.imageUrl
} else {
imageLearner.source = "../images/user-identity.png"
}
}
}
}
Label {
......@@ -82,7 +69,6 @@ Item {
text: root.profile != null ? root.profile.name : ""
}
Row {
id: editComponent
spacing: 10
......@@ -100,13 +86,20 @@ Item {
Button {
iconName: "edit-delete"
text: i18n("Delete")
enabled: profileManager.profileCount > 1
enabled: g_profileManager.profileCount > 1
onClicked: root.state = "deleteConfirmation"
}
Button {
iconName: "insert-image"
text: i18n("Change Image")
onClicked: profileManager.openImageFileDialog()
onClicked: g_profileManager.openImageFileDialog()
}
ToolButton {
iconName: "edit-clear"
text: i18n("Clear Image")
onClicked: {
g_profileManager.activeProfile.clearImage()
}
}
}
......@@ -148,10 +141,10 @@ Item {
onClicked: {
root.profile.name = profileForm.name
if (root.profile.id === -1) {
profileManager.addProfile(profile)
g_profileManager.addProfile(profile)
}
else {
profileManager.sync(root.profile)
g_profileManager.sync(root.profile)
}
root.update()
root.state = "info"
......@@ -203,7 +196,6 @@ Item {
}
}
states: [
State {
name: "info"
......
......@@ -58,12 +58,6 @@ Item {
anchors.fill: parent
color: theme.backgroundColor
opacity: 1.0
Behavior on opacity {
NumberAnimation {
duration: 300
}
}
}
ColumnLayout {
......
......@@ -100,7 +100,7 @@ Item {
Layout.preferredHeight: main.height / 2
color: "lightsteelblue"
QIconItem {
ProfileUserImageItem {
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
......@@ -108,7 +108,7 @@ Item {
bottomMargin: rowSoundControls.height + theme.spacing
}
width: height
icon: "user-identity"
profile: g_profileManager.activeProfile
}
Row {
id: rowSoundControls
......
......@@ -15,9 +15,11 @@
<file>PhraseEditorEditStateComponent.qml</file>
<file>PhraseEditorSoundComponent.qml</file>
<file>PhraseEditorTypeComponent.qml</file>
<file>ProfileSettingsItem.qml</file>
<file>ProfileDetailsItem.qml</file>
<file>ProfileDetailsViewFavorites.qml</file>
<file>ProfileDetailsViewUser.qml</file>
<file>ProfileUserItem.qml</file>
<file>ProfileUserImageItem.qml</file>
<file>ProfileSelector.qml</file>
<file>SheetDialog.qml</file>
<file>SoundPlayer.qml</file>
......
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