Git commit 59036e061ab35277fe7c0254234ec8f1374a3517 by Jaroslaw Staniek. Committed on 23/01/2012 at 23:43. Pushed by staniek into branch 'master'.
GUI: prototype of welcome status bar feedback format++: added JSON-compatible character escaping; added uid M +1 -0 kexi/main/CMakeLists.txt M +47 -4 kexi/main/KexiUserFeedbackAgent.cpp M +11 -2 kexi/main/startup/KexiWelcomeAssistant.cpp M +2 -0 kexi/main/startup/KexiWelcomeAssistant.h A +200 -0 kexi/main/startup/KexiWelcomeStatusBar.cpp [License: LGPL (v2+)] A +48 -0 kexi/main/startup/KexiWelcomeStatusBar.h [License: LGPL (v2+)] http://commits.kde.org/calligra/59036e061ab35277fe7c0254234ec8f1374a3517 diff --git a/kexi/main/CMakeLists.txt b/kexi/main/CMakeLists.txt index 40e883b..1c1f3d6 100644 --- a/kexi/main/CMakeLists.txt +++ b/kexi/main/CMakeLists.txt @@ -26,6 +26,7 @@ KexiUserFeedbackAgent.cpp startup/KexiNewProjectAssistant.cpp startup/KexiOpenProjectAssistant.cpp startup/KexiWelcomeAssistant.cpp +startup/KexiWelcomeStatusBar.cpp startup/KexiImportExportAssistant.cpp startup/KexiStartupFileHandler.cpp startup/KexiStartupDialog.cpp diff --git a/kexi/main/KexiUserFeedbackAgent.cpp b/kexi/main/KexiUserFeedbackAgent.cpp index 083f748..2ecee1d 100644 --- a/kexi/main/KexiUserFeedbackAgent.cpp +++ b/kexi/main/KexiUserFeedbackAgent.cpp @@ -25,13 +25,21 @@ #include <KIO/Job> #include <KLocale> #include <KDebug> +#include <KConfigGroup> #include <QPair> #include <QApplication> #include <QDesktopWidget> #include <QProcess> +#include <QUuid> -static const char userFeedbackUrl[] = "http://www.kexi-project.org/feedback/send"; +//! Version of feedback data format. +//! Changelog: +//! *1.0: initial version +//! *1.1: added JSON-compatible character escaping; added uid +static const char KexiUserFeedbackAgent_VERSION[] = "1.1"; + +static const char KexiUserFeedbackAgent_URL[] = "http://www.kexi-project.org/feedback/send"; typedef QPair<QByteArray, QVariant> DataPair; @@ -44,13 +52,27 @@ public: } bool enabled; QList<DataPair> data; + //! Unique user ID handy if used does not want to disclose username + //! but agrees to be identified as unique user of the application. + QUuid uid; }; KexiUserFeedbackAgent::KexiUserFeedbackAgent(QObject* parent) : QObject(parent), d(new Private) { + KConfigGroup configGroup(KGlobal::config()->group("User Feedback")); + + // load or create uid + QString uidString = configGroup.readEntry("uid", QString()); + d->uid = QUuid(uidString); + if (d->uid.isNull()) { + d->uid = QUuid::createUuid(); + configGroup.writeEntry("uid", d->uid.toString()); + } + #define ADD(a, b) d->data.append(qMakePair(QByteArray(a), QVariant(b))) - ADD("ver", "1.0"); + ADD("ver", KexiUserFeedbackAgent_VERSION); + ADD("uid", d->uid.toString()); ADD("app_ver", Kexi::versionString()); ADD("app_ver_major", Kexi::versionMajor()); ADD("app_ver_minor", Kexi::versionMinor()); @@ -116,6 +138,26 @@ void KexiUserFeedbackAgent::setEnabled(bool enabled) d->enabled = enabled; } +//! Escapes string for json format (see http://json.org/string.gif). +inline QString escapeJson(const QString& s) +{ + QString res; + for (int i=0; i<s.length(); i++) { + switch (s[i].toLatin1()) { + case '\\': res += QLatin1String("\\\\"); break; + case '/': res += QLatin1String("\\/"); break; + case '"': res += QLatin1String("\\\""); break; + case '\b': res += QLatin1String("\\b"); break; + case '\f': res += QLatin1String("\\f"); break; + case '\n': res += QLatin1String("\\n"); break; + case '\r': res += QLatin1String("\\r"); break; + case '\t': res += QLatin1String("\\t"); break; + default: res += s[i]; + } + } + return res; +} + void KexiUserFeedbackAgent::sendData() { QByteArray postData; @@ -124,11 +166,12 @@ void KexiUserFeedbackAgent::sendData() postData += ','; } postData += (QByteArray("\"") + item.first + "\":\"" - + item.second.toString().toUtf8() + '"'); + + escapeJson(item.second.toString()).toUtf8() + '"'); } + kDebug() << postData; KIO::Job* sendJob = KIO::storedHttpPost( - postData, KUrl(userFeedbackUrl), KIO::HideProgressInfo); + postData, KUrl(KexiUserFeedbackAgent_URL), KIO::HideProgressInfo); connect(sendJob, SIGNAL(finished(KJob*)), this, SLOT(sendJobFinished(KJob*))); sendJob->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded"); } diff --git a/kexi/main/startup/KexiWelcomeAssistant.cpp b/kexi/main/startup/KexiWelcomeAssistant.cpp index 6f2a60f..9f0c9ed 100644 --- a/kexi/main/startup/KexiWelcomeAssistant.cpp +++ b/kexi/main/startup/KexiWelcomeAssistant.cpp @@ -1,5 +1,5 @@ /* This file is part of the KDE project - Copyright (C) 2011 Jaros?aw Staniek <staniek at kde.org> + Copyright (C) 2011-2012 Jaros?aw Staniek <staniek at kde.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -20,6 +20,7 @@ #include "KexiWelcomeAssistant.h" #include "KexiRecentProjectsModel.h" +#include "KexiWelcomeStatusBar.h" #include <core/kexi.h> #include <core/KexiRecentProjects.h> @@ -66,7 +67,11 @@ KexiMainWelcomePage::KexiMainWelcomePage( { connect(this, SIGNAL(openProject(KexiProjectData,QString,bool*)), assistant, SIGNAL(openProject(KexiProjectData,QString,bool*))); + QWidget* contents = new QWidget; + QHBoxLayout* contentsLyr = new QHBoxLayout(contents); + m_recentProjects = new KexiCategorizedView; + contentsLyr->addWidget(m_recentProjects, 1); //m_recentProjects->setItemDelegate(new KFileItemDelegate(this)); setFocusWidget(m_recentProjects); m_recentProjects->setFrameShape(QFrame::NoFrame); @@ -77,7 +82,11 @@ KexiMainWelcomePage::KexiMainWelcomePage( m_recentProjects->setSpacing(margin); m_recentProjects->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); connect(m_recentProjects, SIGNAL(clicked(QModelIndex)), this, SLOT(slotItemClicked(QModelIndex))); - setContents(m_recentProjects); + + m_statusBar = new KexiWelcomeStatusBar; + contentsLyr->addWidget(m_statusBar); + + setContents(contents); QTimer::singleShot(100, this, SLOT(loadProjects())); } diff --git a/kexi/main/startup/KexiWelcomeAssistant.h b/kexi/main/startup/KexiWelcomeAssistant.h index 98319cc..a8d892d 100644 --- a/kexi/main/startup/KexiWelcomeAssistant.h +++ b/kexi/main/startup/KexiWelcomeAssistant.h @@ -34,6 +34,7 @@ class KexiProjectSelectorWidget; class KCategorizedView; class KexiWelcomeAssistant; class KexiRecentProjectsProxyModel; +class KexiWelcomeStatusBar; class KexiMainWelcomePage : public KexiAssistantPage { @@ -55,6 +56,7 @@ private: KexiCategorizedView* m_recentProjects; KexiRecentProjectsProxyModel* m_recentProjectsProxyModel; KexiWelcomeAssistant* m_assistant; + KexiWelcomeStatusBar* m_statusBar; }; class KexiProjectData; diff --git a/kexi/main/startup/KexiWelcomeStatusBar.cpp b/kexi/main/startup/KexiWelcomeStatusBar.cpp new file mode 100644 index 0000000..384de2f --- /dev/null +++ b/kexi/main/startup/KexiWelcomeStatusBar.cpp @@ -0,0 +1,200 @@ +/* This file is part of the KDE project + Copyright (C) 2011-2012 Jaros?aw Staniek <staniek at kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "KexiWelcomeStatusBar.h" +#include <kexiutils/utils.h> + +#include <KTextBrowser> +#include <KGlobalSettings> +#include <KIconLoader> +#include <KColorUtils> +#include <KColorScheme> +#include <KStandardDirs> +#include <KDebug> + +#include <QLayout> +#include <QProgressBar> +#include <QtCore/qmath.h> + +#define HEADER_SIZE 1.0 + +class KexiStatusTextDocument : public QTextDocument +{ +public: + KexiStatusTextDocument(KexiWelcomeStatusBar* parent) : QTextDocument(parent), + m_parent(parent) + { + // http://www.qtcentre.org/wiki/index.php?title=QTextBrowser_with_images_and_CSS + qreal fontSize = qFloor( + (KGlobalSettings::smallestReadableFont().pointSizeF() + + m_parent->font().pointSizeF()) + / 2.0); + KColorScheme colorScheme(m_parent->palette().currentColorGroup()); + QString css = + QString("* { font-size:%1pt; color:%2; } ") + .arg(fontSize).arg(m_parent->palette().color(QPalette::Text).name()) + + QString(".gray, .gray * { color:%1; } ") + .arg(KColorUtils::mix(m_parent->palette().color(QPalette::Text), + m_parent->palette().color(QPalette::Base), 0.5).name()) + + "img.icon { vertical-align:bottom; } " + //+ "body { background-color:yellow; } " + + "p { text-indent:0px; } " + + QString("*.head { text-indent:0px; font-size:%1pt; font-weight:bold; } ").arg( + m_parent->font().pointSizeF() * HEADER_SIZE) + + QString("a, a * { color:%1; } ") + .arg(colorScheme.foreground(KColorScheme::LinkText).color().name()); + addResource(QTextDocument::StyleSheetResource, QUrl( "format.css" ), css); + } +protected: + virtual QVariant loadResource(int type, const QUrl &name) + { + if (type == QTextDocument::ImageResource) { + if (name.scheme() == QLatin1String("kicon")) { + return KIconLoader::global()->loadIcon(name.host(), KIconLoader::NoGroup, 16); + } + else if (name.scheme() == "feedbackdata") { + if (name.host() == "progress") { + return m_parent->userProgressPixmap(); + } + } + else if (name.toString() == "ext") { + return m_parent->externalLinkPixmap(); + } + } + return QTextDocument::loadResource(type, name); + } +private: + KexiWelcomeStatusBar *m_parent; +}; + +//--- + +class KexiWelcomeStatusBar::Private +{ +public: + Private(KexiWelcomeStatusBar* _q) + : q(_q) + { + } + + KTextBrowser *statusBrowser; + QProgressBar userProgressBar; + QVBoxLayout *lyr; + QPixmap externalLinkPixmap; +private: + KexiWelcomeStatusBar *q; +}; + +KexiWelcomeStatusBar::KexiWelcomeStatusBar(QWidget* parent) + : QWidget(parent), d(new Private(this)) +{ + d->lyr = new QVBoxLayout(this); + d->userProgressBar.setTextVisible(false); + setUserProgress(5); + + init(); +} + +KexiWelcomeStatusBar::~KexiWelcomeStatusBar() +{ + delete d; +} + +void KexiWelcomeStatusBar::init() +{ + QString title("You in Kexi Project"); // Your Status in Kexi Project + QString html = QString( + "<p><span class=\"head\">%1</span> <a class='gray' href='feedback://help_your_status'>(?)</a></p>" + "<p><img src='feedbackdata://progress'> <b>%2%</b> involved</p>" + "<p><b>Contribute</b> <a class='gray' href='feedback://help_why_contribute'>(Why?)</a></p>" + "<p><img src=\"kicon://list-add\"> <a href='feedback://show_share_usage_info'>Share Usage Info</a> <span class='gray'>(+5%)</span></p>" + ).arg(title).arg(d->userProgressBar.value()); + + d->statusBrowser = new KTextBrowser; + d->statusBrowser->setFrameShape(QFrame::NoFrame); + d->statusBrowser->setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::LinksAccessibleByKeyboard); + d->lyr->addWidget(d->statusBrowser); + + KexiStatusTextDocument *doc = new KexiStatusTextDocument(this); + + QFont f(d->statusBrowser->font()); + f.setBold(true); + f.setPointSizeF(f.pointSizeF() * HEADER_SIZE); + d->statusBrowser->setFixedWidth(QFontMetrics(f).width(title + "(?)_____")); + d->userProgressBar.setFixedSize( + d->statusBrowser->minimumWidth() - QFontMetrics(f).width("888% involved"), + fontMetrics().height()); + //statusDoc->addResource(QTextDocument::ImageResource, QUrl( "bg.png" ), QPixmap(":bg")); + + title = "What's New?"; + // <img src='ext'> + html += QString( + "<br>" + "<p><b class=\"head\">%1</b></p>" + "<p><a href=\"newsdata://0\"> Fruits of CSS2: Office Forms</a></p>" + "<p align=\"right\"><a href=\"newsdata://show_all\">See all <b>News</b> »</a></p>" + ).arg(title); + + title = "Recent Releases"; + html += QString( + "<br>" + "<p><b class=\"head\">%1</b></p>" + "<p><table>" + "<tr><td><p>Stable release: </p></td><td><a href=\"http://www.koffice.org/news/announcements/koffice-2-3-3-update/\">2.3.3</a></td></tr>" + "<tr><td><p>Preview release: </p></td><td><a href=\"http://www.calligra.org/news/announcements/calligra-2-4-beta-6/\">2.4 Beta 6</a></td></tr>" + "</table></p>" + "<p align=\"right\"><a href=\"newsdata://show_all\">See more <b>Releases</b> »</a></p>" + ).arg(title); + + QString htmlHead(QLatin1String( + "<html><head>" + "<link rel='stylesheet' type='text/css' href='format.css'>" + "</head><body>")); + doc->setHtml(htmlHead + html + "</body></html>"); + d->statusBrowser->setDocument(doc); + kDebug() << d->statusBrowser->toHtml(); +} + +void KexiWelcomeStatusBar::setUserProgress(int progress) +{ + d->userProgressBar.setValue(progress); +} + +QPixmap KexiWelcomeStatusBar::userProgressPixmap() +{ + QPixmap px(d->userProgressBar.size()); + px.fill(Qt::transparent); + QPainter p(&px); + p.setOpacity(0.5); + d->userProgressBar.render(&p); + return px; +} + +QPixmap KexiWelcomeStatusBar::externalLinkPixmap() +{ + if (d->externalLinkPixmap.isNull()) { + d->externalLinkPixmap = QPixmap( + KStandardDirs::locate("data", "kexi/pics/external-link.png")); + KColorScheme colorScheme(palette().currentColorGroup()); + QColor c(colorScheme.foreground(KColorScheme::LinkText).color()); + c.setAlpha(100); + KexiUtils::replaceColors(&d->externalLinkPixmap, c); + } + return d->externalLinkPixmap; +} diff --git a/kexi/main/startup/KexiWelcomeStatusBar.h b/kexi/main/startup/KexiWelcomeStatusBar.h new file mode 100644 index 0000000..f2fb1ab --- /dev/null +++ b/kexi/main/startup/KexiWelcomeStatusBar.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2012 Jaros?aw Staniek <staniek at kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KEXIWELCOMESTATUSBAR_H +#define KEXIWELCOMESTATUSBAR_H + +#include <QWidget> + +//! Status sidebar for the welcome page +class KexiWelcomeStatusBar : public QWidget +{ + Q_OBJECT +public: + explicit KexiWelcomeStatusBar(QWidget* parent = 0); + ~KexiWelcomeStatusBar(); + + QPixmap userProgressPixmap(); + QPixmap externalLinkPixmap(); + +signals: + +private slots: + +private: + void setUserProgress(int progress); + void init(); + + class Private; + Private * const d; +}; + +#endif
