diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2012-06-27 08:22:11 (GMT) |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2012-06-27 08:22:11 (GMT) |
commit | e51f456146457a444dab9c477c8e21bcd9faf9b4 (patch) | |
tree | ee4f5186d6e58c7a4136bf915e9c3b2efa4c5576 /notes | |
parent | ad466258dc5a568260c33808827b8870777a69f7 (diff) | |
download | libcalendaring-e51f456146457a444dab9c477c8e21bcd9faf9b4.tar.gz |
akonadi notes
Diffstat (limited to 'notes')
-rw-r--r-- | notes/CMakeLists.txt | 45 | ||||
-rwxr-xr-x | notes/Messages.sh | 2 | ||||
-rw-r--r-- | notes/akonadi-notes_export.h | 39 | ||||
-rw-r--r-- | notes/noteutils.cpp | 546 | ||||
-rw-r--r-- | notes/noteutils.h | 272 | ||||
-rw-r--r-- | notes/tests/CMakeLists.txt | 6 | ||||
-rw-r--r-- | notes/tests/notestest.cpp | 85 |
7 files changed, 995 insertions, 0 deletions
diff --git a/notes/CMakeLists.txt b/notes/CMakeLists.txt new file mode 100644 index 0000000..941a324 --- /dev/null +++ b/notes/CMakeLists.txt @@ -0,0 +1,45 @@ +project(akonadi-notes) + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") +cmake_minimum_required(VERSION 2.6) + +# only available from cmake-2.8.0 +if(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} GREATER 7) + cmake_policy(SET CMP0012 NEW) +endif() + +# only available from cmake-2.8.4 +if(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} GREATER 7 AND + ${CMAKE_PATCH_VERSION} GREATER 3) + cmake_policy(SET CMP0017 NEW) +endif() + +find_package(Qt4 4.6.0 REQUIRED) + +include_directories(${QT_INCLUDES}) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -UQT_NO_CAST_FROM_ASCII -UQT_NO_CAST_TO_ASCII ${KDE4_ENABLE_EXCEPTIONS}") + +set(akonadinotes_LIB_SRC + noteutils.cpp +) +add_library(calendaring-akonadi-notes ${LIBRARY_TYPE} ${akonadinotes_LIB_SRC}) + +target_link_libraries(calendaring-akonadi-notes calendaring-kmime ${QT_QTXML_LIBRARY}) + +set_target_properties(calendaring-akonadi-notes PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) + +install(TARGETS calendaring-akonadi-notes EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) + +install( FILES + noteutils.h + akonadi-notes_export.h + DESTINATION ${INCLUDE_INSTALL_DIR}/akonadi/notes COMPONENT Devel +) + +# add_subdirectory(tests) diff --git a/notes/Messages.sh b/notes/Messages.sh new file mode 100755 index 0000000..5112a04 --- /dev/null +++ b/notes/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT *.cpp -o $podir/akonadinotes.pot diff --git a/notes/akonadi-notes_export.h b/notes/akonadi-notes_export.h new file mode 100644 index 0000000..0a4f72c --- /dev/null +++ b/notes/akonadi-notes_export.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + Copyright (C) 2011 Christian Mollekopf <chrigi_1@fastmail.fm> + + This library 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 library 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 library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef AKONADI_NOTES_EXPORT_H +#define AKONADI_NOTES_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include <kdemacros.h> + +#ifndef AKONADI_NOTES_EXPORT +# if defined(KDEPIM_STATIC_LIBS) + /* No export/import for static libraries */ +# define AKONADI_NOTES_EXPORT +# elif defined(MAKE_AKONADI_NOTES_LIB) + /* We are building this library */ +# define AKONADI_NOTES_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define AKONADI_NOTES_EXPORT KDE_IMPORT +# endif +#endif + +#endif diff --git a/notes/noteutils.cpp b/notes/noteutils.cpp new file mode 100644 index 0000000..2ea47a5 --- /dev/null +++ b/notes/noteutils.cpp @@ -0,0 +1,546 @@ +/* This file is part of the KDE project + Copyright (C) 2011 Christian Mollekopf <chrigi_1@fastmail.fm> + + This library 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 library 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 library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "noteutils.h" + +#include <klocalizedstring.h> +#include <kdatetime.h> +#include <kmime/kmime_message.h> +#include <kdebug.h> + +#include <qstring.h> +#include <quuid.h> +#include <qdom.h> + +namespace Akonadi { +namespace NoteUtils { + +#define X_NOTES_UID_HEADER "X-Akonotes-UID" +#define X_NOTES_LASTMODIFIED_HEADER "X-Akonotes-LastModified" +#define X_NOTES_CLASSIFICATION_HEADER "X-Akonotes-Classification" +#define X_NOTES_CUSTOM_HEADER "X-Akonotes-Custom" + +#define CLASSIFICATION_PUBLIC "Public" +#define CLASSIFICATION_PRIVATE "Private" +#define CLASSIFICATION_CONFIDENTIAL "Confidential" + +#define X_NOTES_URL_HEADER "X-Akonotes-Url" +#define X_NOTES_LABEL_HEADER "X-Akonotes-Label" +#define X_NOTES_CONTENTTYPE_HEADER "X-Akonotes-Type" +#define CONTENT_TYPE_CUSTOM "custom" +#define CONTENT_TYPE_ATTACHMENT "attachment" + +#define ENCODING "utf-8" + +class Attachment::AttachmentPrivate +{ + public: + AttachmentPrivate( const QUrl& url, const QString& mimetype ) + : mUrl( url ), + mMimetype( mimetype ) + {} + + AttachmentPrivate( const QByteArray& data, const QString& mimetype ) + : mData( data ), + mMimetype( mimetype ) + {} + + AttachmentPrivate( const AttachmentPrivate &other ) + { + *this = other; + } + + QUrl mUrl; + QByteArray mData; + QString mMimetype; + QString mLabel; +}; + + +Attachment::Attachment( const QUrl& url, const QString& mimetype ) +: d_ptr( new Attachment::AttachmentPrivate( url, mimetype ) ) +{ +} + +Attachment::Attachment( const QByteArray& data, const QString& mimetype ) +: d_ptr( new Attachment::AttachmentPrivate( data, mimetype ) ) +{ +} + +Attachment::Attachment( const Attachment &other ) +: d_ptr(new AttachmentPrivate(*other.d_func()) ) +{ + +} + +Attachment::~Attachment() +{ + delete d_ptr; +} + + +bool Attachment::operator==( const Attachment &a ) const +{ + const Q_D( Attachment ); + if ( d->mUrl.isEmpty() ) { + return d->mUrl == a.d_func()->mUrl && + d->mMimetype == a.d_func()->mMimetype && + d->mLabel == a.d_func()->mLabel; + } + return d->mData == a.d_func()->mData && + d->mMimetype == a.d_func()->mMimetype && + d->mLabel == a.d_func()->mLabel; +} + +void Attachment::operator=( const Attachment &a ) +{ + *d_ptr = *a.d_ptr; +} + +QUrl Attachment::url() const +{ + const Q_D( Attachment ); + return d->mUrl; +} + +QByteArray Attachment::data() const +{ + const Q_D( Attachment ); + return d->mData; +} + +QString Attachment::mimetype() const +{ + const Q_D( Attachment ); + return d->mMimetype; +} + +void Attachment::setLabel( const QString& label ) +{ + Q_D( Attachment ); + d->mLabel = label; +} + +QString Attachment::label() const +{ + const Q_D( Attachment ); + return d->mLabel; +} + + + +class NoteMessageWrapper::NoteMessageWrapperPrivate +{ + public: + NoteMessageWrapperPrivate() + : classification( Public ) + { + } + + NoteMessageWrapperPrivate( const KMime::Message::Ptr &msg ) + : textFormat( Qt::PlainText ), + classification( Public ) + { + readMimeMessage(msg); + } + + void readMimeMessage(const KMime::Message::Ptr &msg ); + + KMime::Content* createCustomPart() const; + void parseCustomPart( KMime::Content * ); + + KMime::Content* createAttachmentPart( const Attachment & ) const; + void parseAttachmentPart( KMime::Content * ); + + QString uid; + QString title; + QString text; + Qt::TextFormat textFormat; + QString from; + KDateTime creationDate; + KDateTime lastModifiedDate; + QMap< QString, QString > custom; + QList<Attachment> attachments; + Classification classification; +}; + +void NoteMessageWrapper::NoteMessageWrapperPrivate::readMimeMessage(const KMime::Message::Ptr& msg) +{ + if (!msg.get()) { + kWarning() << "Empty message"; + return; + } + title = msg->subject( true )->asUnicodeString(); + text = msg->mainBodyPart()->decodedText( true ); //remove trailing whitespace, so we get rid of " " in empty notes + if ( msg->from( false ) ) + from = msg->from( false )->asUnicodeString(); + creationDate = msg->date( true )->dateTime(); + if ( msg->contentType( false ) && msg->contentType( false )->asUnicodeString() == QLatin1String("text/html") ) { + textFormat = Qt::RichText; + } + + if (KMime::Headers::Base *lastmod = msg->headerByType(X_NOTES_LASTMODIFIED_HEADER)) { + const QByteArray &s = lastmod->asUnicodeString().toLatin1(); + const char *cursor = s.constData(); + if (!KMime::HeaderParsing::parseDateTime( cursor, cursor + s.length(), lastModifiedDate)) { + kWarning() << "failed to parse lastModifiedDate"; + } + } + + if (KMime::Headers::Base *uidHeader = msg->headerByType(X_NOTES_UID_HEADER)) { + uid = uidHeader->asUnicodeString(); + } + + if (KMime::Headers::Base *classificationHeader = msg->headerByType(X_NOTES_CLASSIFICATION_HEADER)) { + const QString &c = classificationHeader->asUnicodeString(); + if ( c == CLASSIFICATION_PRIVATE ) { + classification = Private; + } else if ( c == CLASSIFICATION_CONFIDENTIAL ) { + classification = Confidential; + } + } + + const KMime::Content::List list = msg->contents(); + Q_FOREACH(KMime::Content *c, msg->contents()) { + if (KMime::Headers::Base *typeHeader = c->headerByType(X_NOTES_CONTENTTYPE_HEADER)) { + const QString &type = typeHeader->asUnicodeString(); + if ( type == CONTENT_TYPE_CUSTOM ) { + parseCustomPart(c); + } else if ( type == CONTENT_TYPE_ATTACHMENT ) { + parseAttachmentPart(c); + } else { + qWarning() << "unknown type " << type; + } + } + } +} + +QDomDocument createXMLDocument() +{ + QDomDocument document; + QString p = "version=\"1.0\" encoding=\"UTF-8\""; + document.appendChild(document.createProcessingInstruction( "xml", p ) ); + return document; +} + +QDomDocument loadDocument(KMime::Content *part) +{ + QString errorMsg; + int errorLine, errorColumn; + QDomDocument document; + bool ok = document.setContent( part->body(), &errorMsg, &errorLine, &errorColumn ); + if ( !ok ) { + kWarning() << part->body(); + qWarning( "Error loading document: %s, line %d, column %d", qPrintable( errorMsg ), errorLine, errorColumn ); + return QDomDocument(); + } + return document; +} + +KMime::Content* NoteMessageWrapper::NoteMessageWrapperPrivate::createCustomPart() const +{ + KMime::Content* content = new KMime::Content(); + content->appendHeader( new KMime::Headers::Generic( X_NOTES_CONTENTTYPE_HEADER, content, CONTENT_TYPE_CUSTOM, ENCODING ) ); + QDomDocument document = createXMLDocument(); + QDomElement element = document.createElement( "custom" ); + element.setAttribute( "version", "1.0" ); + for ( QMap <QString, QString >::const_iterator it = custom.begin(); it != custom.end(); ++it ) { + QDomElement e = element.ownerDocument().createElement( it.key() ); + QDomText t = element.ownerDocument().createTextNode( it.value() ); + e.appendChild( t ); + element.appendChild( e ); + document.appendChild( element ); + } + content->setBody( document.toString().toLatin1() ); + return content; +} + +void NoteMessageWrapper::NoteMessageWrapperPrivate::parseCustomPart( KMime::Content* part ) +{ + QDomDocument document = loadDocument( part ); + if (document.isNull()) { + return; + } + QDomElement top = document.documentElement(); + if ( top.tagName() != "custom" ) { + qWarning( "XML error: Top tag was %s instead of the expected custom", + top.tagName().toAscii().data() ); + return; + } + + for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) { + if ( n.isElement() ) { + QDomElement e = n.toElement(); + custom.insert(e.tagName(), e.text()); + } else { + kDebug() <<"Node is not an element"; + Q_ASSERT(false); + } + } +} + +KMime::Content* NoteMessageWrapper::NoteMessageWrapperPrivate::createAttachmentPart( const Attachment &a ) const +{ + KMime::Content* content = new KMime::Content(); + content->appendHeader( new KMime::Headers::Generic( X_NOTES_CONTENTTYPE_HEADER, content, CONTENT_TYPE_ATTACHMENT, ENCODING ) ); + if (a.url().isValid()) { + content->appendHeader( new KMime::Headers::Generic( X_NOTES_URL_HEADER, content, a.url().toString().toLatin1(), ENCODING ) ); + } else { + content->setBody( a.data() ); + } + content->contentType()->setMimeType( a.mimetype().toLatin1() ); + if (!a.label().isEmpty()) { + content->appendHeader( new KMime::Headers::Generic( X_NOTES_LABEL_HEADER, content, a.label().toLatin1(), ENCODING ) ); + } + content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 ); + content->contentDisposition()->setDisposition( KMime::Headers::CDattachment ); + content->contentDisposition()->setFilename( "attachment" ); + return content; +} + +void NoteMessageWrapper::NoteMessageWrapperPrivate::parseAttachmentPart( KMime::Content *part ) +{ + QString label; + if ( KMime::Headers::Base *labelHeader = part->headerByType( X_NOTES_LABEL_HEADER ) ) { + label = labelHeader->asUnicodeString(); + } + if ( KMime::Headers::Base *header = part->headerByType( X_NOTES_URL_HEADER ) ) { + Attachment attachment( QUrl( header->asUnicodeString() ), part->contentType()->mimeType() ); + attachment.setLabel( label ); + attachments.append(attachment); + } else { + Attachment attachment( part->decodedContent(), part->contentType()->mimeType() ); + attachment.setLabel( label ); + attachments.append(attachment); + } +} + +NoteMessageWrapper::NoteMessageWrapper() +: d_ptr( new NoteMessageWrapperPrivate() ) +{ +} + +NoteMessageWrapper::NoteMessageWrapper( const KMime::Message::Ptr &msg ) +: d_ptr( new NoteMessageWrapperPrivate(msg) ) +{ +} + +NoteMessageWrapper::~NoteMessageWrapper() +{ + delete d_ptr; +} + +KMime::Message::Ptr NoteMessageWrapper::message() const +{ + const Q_D( NoteMessageWrapper ); + KMime::Message::Ptr msg = KMime::Message::Ptr( new KMime::Message() ); + + QString title = i18nc( "The default name for new notes.", "New Note" ); + if ( !d->title.isEmpty() ) { + title = d->title; + } + // Need a non-empty body part so that the serializer regards this as a valid message. + QString text = QLatin1String(" "); + if ( !d->text.isEmpty() ) { + text = d->text; + } + + KDateTime creationDate = KDateTime::currentLocalDateTime(); + if ( d->creationDate.isValid() ) { + creationDate = d->creationDate; + } + + KDateTime lastModifiedDate = KDateTime::currentLocalDateTime(); + if ( d->lastModifiedDate.isValid() ) { + lastModifiedDate = d->lastModifiedDate; + } + + QString uid; + if ( !d->uid.isEmpty() ) { + uid = d->uid; + } else { + uid = QUuid::createUuid(); + } + + msg->subject( true )->fromUnicodeString( title, ENCODING ); + msg->contentType( true )->setMimeType( d->textFormat == Qt::RichText ? "text/html" : "text/plain" ); + msg->date( true )->setDateTime( creationDate ); + msg->from( true )->fromUnicodeString( d->from, ENCODING ); + msg->mainBodyPart()->fromUnicodeString( text ); + msg->appendHeader( new KMime::Headers::Generic(X_NOTES_LASTMODIFIED_HEADER, msg.get(), lastModifiedDate.toString( KDateTime::RFCDateDay ).toLatin1(), ENCODING ) ); + msg->appendHeader( new KMime::Headers::Generic( X_NOTES_UID_HEADER, msg.get(), uid, ENCODING ) ); + + QString classification = QString::fromLatin1(CLASSIFICATION_PUBLIC); + switch ( d->classification ) { + case Private: + classification = QString::fromLatin1(CLASSIFICATION_PRIVATE); + break; + case Confidential: + classification = QString::fromLatin1(CLASSIFICATION_CONFIDENTIAL); + break; + default: + //do nothing + break; + } + msg->appendHeader( new KMime::Headers::Generic( X_NOTES_CLASSIFICATION_HEADER, msg.get(), classification, ENCODING ) ); + + foreach (const Attachment &a, d->attachments) { + msg->addContent( d->createAttachmentPart(a) ); + } + + if ( !d->custom.isEmpty() ) { + msg->addContent( d->createCustomPart() ); + } + + msg->assemble(); + return msg; +} + +void NoteMessageWrapper::setUid( const QString &uid ) +{ + Q_D( NoteMessageWrapper ); + d->uid = uid; +} + +QString NoteMessageWrapper::uid() const +{ + const Q_D( NoteMessageWrapper ); + return d->uid; +} + +void NoteMessageWrapper::setClassification( NoteMessageWrapper::Classification classification ) +{ + Q_D( NoteMessageWrapper ); + d->classification = classification; +} + +NoteMessageWrapper::Classification NoteMessageWrapper::classification() const +{ + const Q_D( NoteMessageWrapper ); + return d->classification; +} + +void NoteMessageWrapper::setLastModifiedDate( const KDateTime& lastModifiedDate ) +{ + Q_D( NoteMessageWrapper ); + d->lastModifiedDate = lastModifiedDate; +} + +KDateTime NoteMessageWrapper::lastModifiedDate() const +{ + const Q_D( NoteMessageWrapper ); + return d->lastModifiedDate; +} + +void NoteMessageWrapper::setCreationDate( const KDateTime &creationDate ) +{ + Q_D( NoteMessageWrapper ); + d->creationDate = creationDate; +} + +KDateTime NoteMessageWrapper::creationDate() const +{ + const Q_D( NoteMessageWrapper ); + return d->creationDate; +} + +void NoteMessageWrapper::setFrom( const QString &from ) +{ + Q_D( NoteMessageWrapper ); + d->from = from; +} + +QString NoteMessageWrapper::from() const +{ + const Q_D( NoteMessageWrapper ); + return d->from; +} + +void NoteMessageWrapper::setTitle( const QString &title ) +{ + Q_D( NoteMessageWrapper ); + d->title = title; +} + +QString NoteMessageWrapper::title() const +{ + const Q_D( NoteMessageWrapper ); + return d->title; +} + +void NoteMessageWrapper::setText( const QString &text, Qt::TextFormat format ) +{ + Q_D( NoteMessageWrapper ); + d->text = text; + d->textFormat = format; +} + +QString NoteMessageWrapper::text() const +{ + const Q_D( NoteMessageWrapper ); + return d->text; +} + +Qt::TextFormat NoteMessageWrapper::textFormat() const +{ + const Q_D( NoteMessageWrapper ); + return d->textFormat; +} + +QString NoteMessageWrapper::toPlainText() const +{ + const Q_D( NoteMessageWrapper ); + if ( d->textFormat == Qt::PlainText ) { + return d->text; + } + + //From cleanHtml in kdepimlibs/kcalutils/incidenceformatter.cpp + QRegExp rx( QLatin1String("<body[^>]*>(.*)</body>"), Qt::CaseInsensitive ); + rx.indexIn( d->text ); + QString body = rx.cap( 1 ); + + return Qt::escape( body.remove( QRegExp( QLatin1String("<[^>]*>") ) ).trimmed() ); +} + +QList<Attachment> &NoteMessageWrapper::attachments() +{ + Q_D( NoteMessageWrapper ); + return d->attachments; +} + +QMap< QString, QString > &NoteMessageWrapper::custom() +{ + Q_D( NoteMessageWrapper ); + return d->custom; +} + + + +QString noteIconName() +{ + return QString::fromLatin1( "text-plain" ); +} + +QString noteMimeType() +{ + return QString::fromLatin1( "text/x-vnd.akonadi.note" ); +} + +} //End Namepsace +} //End Namepsace diff --git a/notes/noteutils.h b/notes/noteutils.h new file mode 100644 index 0000000..518e84e --- /dev/null +++ b/notes/noteutils.h @@ -0,0 +1,272 @@ +/* This file is part of the KDE project + Copyright (C) 2011 Christian Mollekopf <chrigi_1@fastmail.fm> + + This library 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 library 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 library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef NOTEUTILS_H +#define NOTEUTILS_H + +#include "akonadi-notes_export.h" + +#include <QtCore/QUrl> +#include <QtGui/QTextEdit> + +class KDateTime; +class QString; + +namespace boost { + template <typename T> class shared_ptr; +} + +namespace KMime { + class Message; + typedef boost::shared_ptr<Message> MessagePtr; +} +namespace Akonadi { +namespace NoteUtils { + +/** +* @return mimetype for notes +* @since 4.8 +*/ +AKONADI_NOTES_EXPORT QString noteMimeType(); + +/** +* @return icon for notes +* @since 4.8 +*/ +AKONADI_NOTES_EXPORT QString noteIconName(); + +/** +* An attachment for a note +* @since 4.9 +*/ +class AKONADI_NOTES_EXPORT Attachment +{ +public: + /** + * Create an attachment referencing a url only + */ + Attachment( const QUrl &url, const QString &mimetype ); + /** + * Create an attachment with the content stored inline + */ + Attachment( const QByteArray &data, const QString &mimetype ); + Attachment( const Attachment & ); + ~Attachment(); + + bool operator==( const Attachment & ) const; + void operator=( const Attachment & ); + + /** + * Returns the url for url-only attachments + */ + QUrl url() const; + + /** + * Returns the date for inline attachments + */ + QByteArray data() const; + + /** + * Returns the mimetype + */ + QString mimetype() const; + + /** + * Sets the label to be presented to the user + */ + void setLabel( const QString &label ); + + /** + * Returns the label of the attachment + */ + QString label() const; +private: + //@cond PRIVATE + class AttachmentPrivate; + AttachmentPrivate * const d_ptr; + Q_DECLARE_PRIVATE( Attachment ) + //@endcond +}; + +/** +* A convenience wrapper around KMime::Message::Ptr for notes +* +* This is the format used by the Akonotes Resource +* +* A note has the following properties: +* uid: globally unique identifier (generated if empty) +* creationDate: timestamp when the note was created (generated if empty) +* lastModified: lastModified (generated if empty) +* classification: one of private, confidential, public. This is only meant as an indication to the user. +* title: title of the note +* text: textual content +* from: author (generated if empty) +* attachments: inline or url only +* custom: key value pair for custom values +* +* Reading a note from an Akonotes akonadi item: +* @code +* if ( item.hasPayload<KMime::Message::Ptr>() ) { +* NoteUtils::NoteMessageWrapper note(item.payload<KMime::Message::Ptr>()); +* kDebug() << note.text(); +* textIsRich = messageWrapper.textFormat() == Qt::RichText; +* } +* @endcode +* +* Setting the note as payload of an akonadi Item +* @code +* item.setMimeType(NoteUtils::noteMimeType()); +* NoteUtils::NoteMessageWrapper note; +* note.setTitle( "title" ); +* note.setText( "text" ); +* note.setFrom( QString::fromLatin1( "MyApplication@kde4" ) ); +* item.setPayload( note.message() ); +* @endcode +* +* @author Christian Mollekopf <chrigi_1@fastmail.fm> +* @since 4.8 +*/ +class AKONADI_NOTES_EXPORT NoteMessageWrapper +{ +public: + NoteMessageWrapper(); + explicit NoteMessageWrapper( const KMime::MessagePtr & ); + ~NoteMessageWrapper(); + + /** + * Set the uid of the note + * @param uid should be globally unique + */ + void setUid( const QString &uid ); + + /** + * Returns the uid of the note + */ + QString uid() const; + + enum Classification { + Public, + Private, + Confidential + }; + + /** + * Set the classification of the note + */ + void setClassification( Classification ); + + /** + * Returns the classification of the note + */ + Classification classification() const; + + /** + * Set the title of the note + */ + void setTitle( const QString &title ); + + /** + * Returns the title of the note + */ + QString title() const; + + /** + * Set the text of the note + * + * @param format only Qt::PlainText and Qt::RichText is supported + */ + void setText( const QString &text, Qt::TextFormat format = Qt::PlainText ); + + /** + * Returns the text of the note + */ + QString text() const; + + /** + * @return Qt::PlainText or Qt::RichText + */ + Qt::TextFormat textFormat() const; + + /** + * @return plaintext version of the text (if richtext) + */ + QString toPlainText() const; + + /** + * Set the creation date of the note (stored in the mime header) + */ + void setCreationDate( const KDateTime &creationDate ); + + /** + * Returns the creation date of the note + */ + KDateTime creationDate() const; + + /** + * Set the lastModified-date of the note + */ + void setLastModifiedDate( const KDateTime &lastModifiedDate ); + + /** + * Returns the lastModified-date of the note + */ + KDateTime lastModifiedDate() const; + + /** + * Set the origin (creator) of the note (stored in the mime header) + * This is usually the application creating the note. + * @param from must be an address in the style of foo@kde.org. + */ + void setFrom( const QString &from ); + + /** + * Returns the origin (creator) of the note + */ + QString from() const; + + /** + * Returns a reference to the list of attachments of the note + */ + QList<Attachment> &attachments(); + + /** + * Returns a reference to the custom-value map + * @return key-value map containing all custom values + */ + QMap<QString, QString> &custom(); + + /** + * Assemble a KMime message with the given values + * + * The message can then i.e. be stored inside an akonadi item + */ + KMime::MessagePtr message() const; + +private: + //@cond PRIVATE + class NoteMessageWrapperPrivate; + NoteMessageWrapperPrivate * const d_ptr; + Q_DECLARE_PRIVATE( NoteMessageWrapper ) + //@endcond +}; + +} +} + +#endif diff --git a/notes/tests/CMakeLists.txt b/notes/tests/CMakeLists.txt new file mode 100644 index 0000000..d507a04 --- /dev/null +++ b/notes/tests/CMakeLists.txt @@ -0,0 +1,6 @@ +set(notestest_SRCS notestest.cpp) + +set(CMAKE_PREFIX_PATH ../) + +kde4_add_unit_test(notestest TESTNAME notestest ${notestest_SRCS}) +target_link_libraries(notestest ${KDE4_KDECORE_LIBS} akonadi-notes kmime ${QT_QTTEST_LIBRARY})
\ No newline at end of file diff --git a/notes/tests/notestest.cpp b/notes/tests/notestest.cpp new file mode 100644 index 0000000..fcf5a0f --- /dev/null +++ b/notes/tests/notestest.cpp @@ -0,0 +1,85 @@ +/* + Copyright (c) 2012 Christian Mollekopf <mollekopf@kolabsys.com> + + This library 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 library 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 library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "noteutils.h" + +#include <QTest> +#include <QHash> +#include <QDebug> + +#include <KDateTime> +#include <kmime/kmime_message.h> + +using namespace Akonadi::NoteUtils; +class NotesTest : public QObject +{ + Q_OBJECT + private slots: + + void testSerializeAndParse() + { + NoteMessageWrapper note; + note.setTitle("title"); + note.setText("title"); + note.setUid("uid"); + note.setClassification(NoteMessageWrapper::Private); + note.setFrom("from@kde.org"); + note.setCreationDate(KDateTime(QDate(2012,3,3), QTime(3,3,3), KDateTime::UTC)); + note.setLastModifiedDate(KDateTime(QDate(2012,3,3), QTime(4,4,4), KDateTime::UTC)); + Attachment a("testfile2", "mimetype/mime3"); + a.setLabel("label"); + note.attachments() << Attachment(QUrl("file://url/to/file"), "mimetype/mime") << Attachment("testfile", "mimetype/mime2") << a; + note.custom().insert("key1", "value1"); + note.custom().insert("key2", "value2"); + note.custom().insert("key3", "value3"); + + KMime::MessagePtr msg = note.message(); +// qWarning() << msg->encodedContent(); + + NoteMessageWrapper result(msg); + + QCOMPARE(result.title(), note.title()); + QCOMPARE(result.text(), note.text()); + QCOMPARE(result.textFormat(), note.textFormat()); + QCOMPARE(result.uid(), note.uid()); + QCOMPARE(result.classification(), note.classification()); + QCOMPARE(result.from(), note.from()); + QCOMPARE(result.creationDate(), note.creationDate()); + QCOMPARE(result.lastModifiedDate(), note.lastModifiedDate()); + QCOMPARE(result.custom(), note.custom()); + QCOMPARE(result.attachments(), note.attachments()); + +// qWarning() << result.message()->encodedContent(); + } + + void createIfEmpty() + { + NoteMessageWrapper note; + NoteMessageWrapper result(note.message()); +// qDebug() << result.uid(); + QVERIFY(!result.uid().isEmpty()); + QVERIFY(result.creationDate().isValid()); + QVERIFY(result.lastModifiedDate().isValid()); + } + +}; + +QTEST_MAIN( NotesTest ) + +#include "notestest.moc" |