├── Readme.pdf ├── Model ├── Utils.h ├── POP3Client.h ├── MailListModel.h ├── IMAPClientSession.h ├── IMAPClientSession.cpp ├── SendMailClient.h ├── MailClient.h ├── ReceiveMailClient.h ├── Account.h ├── MailBody.h ├── SMTPClient.h ├── Attachment.h └── IMAPClient.h ├── icons ├── remove.svg ├── forward.svg ├── send.svg ├── add.svg ├── flag.svg ├── menu.svg ├── sort.svg ├── filter_list.svg ├── reply.svg ├── remove_circle.svg ├── reply_all.svg ├── folder.svg ├── text_format.svg ├── add_circle.svg ├── clear.svg ├── add_box.svg ├── folder_open.svg ├── mail.svg ├── person.svg ├── markunread.svg ├── create.svg ├── undo.svg ├── redo.svg ├── content_copy.svg ├── inbox.svg ├── save.svg ├── drafts.svg ├── person_add.svg ├── remove_circle_outline.svg ├── add_circle_outline.svg ├── font_download.svg ├── report.svg ├── move_to_inbox.svg ├── refresh.svg ├── search.svg ├── content_paste.svg ├── next_week.svg ├── link.svg ├── archive.svg ├── backspace.svg ├── block.svg ├── weekend.svg ├── unarchive.svg ├── select_all.svg ├── content_cut.svg └── gesture.svg ├── deployment.pri ├── MyButton.qml ├── Exception ├── MailSendException.h ├── MailReceiveException.h ├── MailClientException.h └── MailGenerationException.h ├── main.cpp ├── MicroMailClient.pro ├── Readme.md ├── qml.qrc ├── AccountLogin.qml ├── MailView.qml ├── main.qml ├── MicroMailClient.pro.user └── NewMailEdit.qml /Readme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stardust95/MicroMailClient/HEAD/Readme.pdf -------------------------------------------------------------------------------- /Model/Utils.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stardust95/MicroMailClient/HEAD/Model/Utils.h -------------------------------------------------------------------------------- /Model/POP3Client.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stardust95/MicroMailClient/HEAD/Model/POP3Client.h -------------------------------------------------------------------------------- /Model/MailListModel.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stardust95/MicroMailClient/HEAD/Model/MailListModel.h -------------------------------------------------------------------------------- /Model/IMAPClientSession.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stardust95/MicroMailClient/HEAD/Model/IMAPClientSession.h -------------------------------------------------------------------------------- /Model/IMAPClientSession.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stardust95/MicroMailClient/HEAD/Model/IMAPClientSession.cpp -------------------------------------------------------------------------------- /icons/remove.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/forward.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/send.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/flag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/menu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/sort.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/filter_list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/reply.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/remove_circle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/reply_all.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/folder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/text_format.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/add_circle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/clear.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/add_box.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/folder_open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/mail.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/person.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/markunread.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/create.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/undo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/redo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/content_copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/inbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/save.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/drafts.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/person_add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/remove_circle_outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/add_circle_outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/font_download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/report.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/move_to_inbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deployment.pri: -------------------------------------------------------------------------------- 1 | unix:!android { 2 | isEmpty(target.path) { 3 | qnx { 4 | target.path = /tmp/$${TARGET}/bin 5 | } else { 6 | target.path = /opt/$${TARGET}/bin 7 | } 8 | export(target.path) 9 | } 10 | INSTALLS += target 11 | } 12 | 13 | export(INSTALLS) 14 | -------------------------------------------------------------------------------- /icons/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/content_paste.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/next_week.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/archive.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/backspace.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/block.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/weekend.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/unarchive.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/select_all.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Model/SendMailClient.h: -------------------------------------------------------------------------------- 1 | #ifndef SENDMAILCLIENT_H 2 | #define SENDMAILCLIENT_H 3 | 4 | #include "MailClient.h" 5 | #include "MailBody.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class SendMailClient : public MailClient{ 12 | 13 | public: 14 | 15 | virtual bool sendMailBodies(const MAILBODY_PTR &) = 0; 16 | 17 | protected: 18 | 19 | }; 20 | 21 | typedef QSharedPointer SENDMAILCLIENT_PTR; 22 | 23 | #endif // SENDMAILCLIENT_H 24 | 25 | -------------------------------------------------------------------------------- /icons/content_cut.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MyButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.6 2 | import QtQuick.Layouts 1.1 3 | import Material 0.2 4 | 5 | Button{ 6 | 7 | property alias source : img.source 8 | 9 | default property alias label : btnLabel.text 10 | 11 | RowLayout{ 12 | 13 | Image{ 14 | id : img 15 | source: "" 16 | scale: iconScale 17 | } 18 | 19 | Label{ 20 | id : btnLabel 21 | anchors.verticalCenter: parent.verticalCenter 22 | text: text 23 | wrapMode: Text.Wrap 24 | width: parent.width 25 | } 26 | 27 | } 28 | 29 | 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Exception/MailSendException.h: -------------------------------------------------------------------------------- 1 | #ifndef MAILSENDEXCEPTION_H 2 | #define MAILSENDEXCEPTION_H 3 | #include "MailClientException.h" 4 | 5 | class MailSendException: public MailClientException 6 | { 7 | public: 8 | MailSendException() { 9 | message = "MailSendException: " + message; 10 | } 11 | MailSendException(const string& exc): MailClientException(exc.c_str()) { 12 | message = "MailSendException: " + message; 13 | } 14 | MailSendException(const MailSendException& mce): MailClientException(mce) { 15 | message = "MailSendException: " + message; 16 | } 17 | ~MailSendException() override {} 18 | const char* what() override{ 19 | return message.c_str(); 20 | } 21 | }; 22 | 23 | #endif // MAILSENDEXCEPTION_H 24 | -------------------------------------------------------------------------------- /icons/gesture.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Exception/MailReceiveException.h: -------------------------------------------------------------------------------- 1 | #ifndef MAILRECEIVEEXCEPTION_H 2 | #define MAILRECEIVEEXCEPTION_H 3 | #include "MailClientException.h" 4 | 5 | class MailReceiveException: public MailClientException 6 | { 7 | public: 8 | MailReceiveException() { 9 | message = "MailReceiveException: " + message; 10 | } 11 | MailReceiveException(const string& exc): MailClientException(exc.c_str()) { 12 | message = "MailReceiveException: " + message; 13 | } 14 | MailReceiveException(const MailReceiveException& mce): MailClientException(mce) { 15 | message = "MailReceiveException: " + message; 16 | } 17 | ~MailReceiveException() override {} 18 | const char* what() override{ 19 | return message.c_str(); 20 | } 21 | }; 22 | 23 | #endif // MAILRECEIVEEXCEPTION_H 24 | -------------------------------------------------------------------------------- /Model/MailClient.h: -------------------------------------------------------------------------------- 1 | #ifndef MAILCLIENT_H 2 | #define MAILCLIENT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class MailClient{ 9 | 10 | public: 11 | 12 | MailClient(){ 13 | _requireSSL = true; 14 | _loginTime = QDateTime::currentDateTime (); 15 | } 16 | 17 | enum ConnectionType{ 18 | TCPConnectoin, SSLConnection, TLSConnection 19 | }; 20 | 21 | virtual bool login(QString, QString, bool) = 0; 22 | 23 | virtual int getTimeout() = 0; 24 | 25 | virtual void setTimeout(int) = 0; 26 | 27 | // virtual ~MailClient() = 0; 28 | 29 | protected: 30 | 31 | QString _host; 32 | QString _port; 33 | QDateTime _loginTime; 34 | bool _requireSSL; 35 | 36 | }; 37 | 38 | typedef QSharedPointer MAILCLIENT_PTR; 39 | 40 | #endif // MAILCLIENT_H 41 | 42 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | //#undef _DEBUG 2 | #include "Model/MailBody.h" 3 | #include "Model/Utils.h" 4 | #include "Model/MailListModel.h" 5 | #include "Model/IMAPClient.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | QGuiApplication app(argc, argv); 27 | 28 | QtWebEngine::initialize (); 29 | 30 | QQmlApplicationEngine engine; 31 | 32 | Models::MailListModel model; 33 | 34 | engine.rootContext ()->setContextProperty("mailListModel", &model); 35 | 36 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 37 | 38 | return app.exec(); 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Exception/MailClientException.h: -------------------------------------------------------------------------------- 1 | #ifndef MAILCLIENTEXCEPTION_H 2 | #define MAILCLIENTEXCEPTION_H 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | class MailClientException: public exception 12 | { 13 | public: 14 | string message; 15 | public: 16 | MailClientException() { 17 | // qDebug() << "MailClientException default Constructor\n"; 18 | message = exception::what(); 19 | } 20 | MailClientException(const string& exc): exception(exc.c_str()) { 21 | // qDebug() << "MailClientException string Constructor\n"; 22 | message = exception::what(); 23 | } 24 | MailClientException(const MailClientException& mce): exception(mce){ 25 | // qDebug() << "MailClientException copy Constructor\n"; 26 | message = exception::what(); 27 | } 28 | virtual ~MailClientException() noexcept = 0 {} 29 | virtual const char* what() = 0; 30 | }; 31 | 32 | 33 | 34 | #endif // MAILCLIENTEXCEPTION_H 35 | -------------------------------------------------------------------------------- /Exception/MailGenerationException.h: -------------------------------------------------------------------------------- 1 | #ifndef MAILGENERATIONEXCEPTION_H 2 | #define MAILGENERATIONEXCEPTION_H 3 | #include "MailClientException.h" 4 | using namespace std; 5 | 6 | class MailGenerationException: public MailClientException 7 | { 8 | public: 9 | MailGenerationException() { 10 | // qDebug() << "MailGenerationException default Constructor\n"; 11 | message = "MailGenerationException: " + message; 12 | } 13 | MailGenerationException(const string& exc): MailClientException(exc.c_str()) { 14 | // qDebug() << "MailGenerationException string Constructor\n"; 15 | message = "MailGenerationException: " + message; 16 | } 17 | MailGenerationException(const MailGenerationException& mce): MailClientException(mce) { 18 | // qDebug() << "MailGenerationException copy Constructor\n"; 19 | message = "MailGenerationException: " + message; 20 | } 21 | ~MailGenerationException() override {} 22 | const char* what() override{ 23 | return message.c_str(); 24 | } 25 | }; 26 | 27 | #endif // MAILGENERATIONEXCEPTION_H 28 | -------------------------------------------------------------------------------- /Model/ReceiveMailClient.h: -------------------------------------------------------------------------------- 1 | #ifndef RECEIVEMAILCLIENT_H 2 | #define RECEIVEMAILCLIENT_H 3 | 4 | #include "MailClient.h" 5 | #include "MailBody.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class ReceiveMailClient : public MailClient{ 13 | 14 | public: 15 | 16 | virtual int getFolders(QList & ) = 0; 17 | 18 | virtual int getMailBodies(QList & , int count) = 0; // DO NOT CLEAR the list in this function 19 | 20 | virtual int DeleteMail(const QList &) = 0; 21 | 22 | virtual int selectFolder(const QString & ) = 0; 23 | 24 | virtual int getAttachment(const Attachment & attach, std::string & outdata) = 0; 25 | 26 | virtual QString getSelectedFolder() final { // final ==> cannot be override 27 | return _selectedFolder; 28 | } 29 | 30 | protected: 31 | 32 | int _curListIndex; 33 | 34 | QString _selectedFolder; 35 | 36 | }; 37 | 38 | typedef QSharedPointer RECEIVEMAILCLIENT_PTR; 39 | 40 | #endif // RECEIVEMAILCLIENT_H 41 | 42 | -------------------------------------------------------------------------------- /MicroMailClient.pro: -------------------------------------------------------------------------------- 1 | 2 | TEMPLATE = app 3 | 4 | QT += qml quick webengine 5 | 6 | qtHaveModule(widgets) { 7 | QT += widgets # QApplication is required to get native styling with QtQuickControls 8 | } 9 | 10 | CONFIG += c++11 11 | 12 | SOURCES += main.cpp \ 13 | Model/IMAPClientSession.cpp 14 | 15 | RESOURCES += qml.qrc 16 | 17 | # Additional import path used to resolve QML modules in Qt Creator's code model 18 | #QML_IMPORT_PATH = 19 | 20 | POCOHOME = "C:\Users\37567\Documents\Visual Studio 2015\Projects\MicroMailClient-QT\PocoLib" 21 | 22 | INCLUDEPATH += "$${POCOHOME}\include" 23 | 24 | LIBS += -L"$${POCOHOME}\Lib" 25 | 26 | # Default rules for deployment. 27 | 28 | include(deployment.pri) 29 | 30 | HEADERS += \ 31 | Model/Account.h \ 32 | Model/Attachment.h \ 33 | Model/IMAPClient.h \ 34 | Model/MailBody.h \ 35 | Model/MailClient.h \ 36 | Model/MailListModel.h \ 37 | Model/Utils.h \ 38 | Model/IMAPClientSession.h \ 39 | Model/ReceiveMailClient.h \ 40 | Model/SendMailClient.h \ 41 | Model/SMTPClient.h \ 42 | Model/POP3Client.h \ 43 | Exception/MailClientException.h \ 44 | Exception/MailGenerationException.h \ 45 | Exception/MailReceiveException.h \ 46 | Exception/MailSendException.h 47 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # MicroMailClient 2 | 3 | 邮件客户端(MVC + QT + Material Design) 4 | 5 | 详细设计文档见 Readme.pdf 6 | 7 | ## 主要功能: 8 | 9 | - 使用MVC设计模式开发的邮件管理客户端(QT + Material Design, 设计参考Gmail移动客户端) 10 | - 用户可以在客户端内使用常用的邮件系统(通过SMTP/POP3)或我们提供的邮件系统MicroMail 11 | - 可以进行邮件及附件的收发, 查看等 12 | 13 | ## 主要模块: 14 | 15 | 1. View(视图)(2人): 16 | - 登陆 17 | - 注册/密码管理(仅使用MicroMail时) 18 | - 收件箱 19 | - 发送邮件 20 | - 查看邮件 21 | - 上传, 下载附件 22 | 23 | 2.Controller(控制器)(1人): 24 | 25 | View与Model(即前端和后端)通信部分程序的实现 26 | 27 | 3.Model(模型)(2人): 28 | 29 | 客户端登录及收发邮件, 查看邮件, 附件下载等的程序实现 30 | 31 | 4.整体架构及接口, 数据库设计(1人) 32 | 33 | 5.MicroMail服务器搭建及程序实现(1人) 34 | 35 | 6.通用(Utils)模块(1人) 36 | 37 | 7.软件开发文档(1人) 38 | 39 | 40 | ## 分工: 41 | 42 | - 视图+整体架构+服务器部分 43 | 44 | - 视图+控制器 45 | 46 | - 模型 47 | 48 | - 开发文档 + 部分模型(网络部分) 49 | 50 | ## P.S. 51 | 52 | 1. 使用git作为版本管理工具, [教程在这里](http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000) 53 | 54 | 2. 全局使用C++11新特性开发, 使用智能指针(shared_ptr, weak_ptr, unique_ptr, 不包括auto_ptr), 减少甚至避免使用new/delete自己管理内存; 使用static_cast<>而非(Type)作类型转换. 55 | 56 | 3. 尽量遵循[Google开源项目的C++风格](http://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/contents/), 尤其是头文件的使用和禁止全局变量. 57 | 58 | 4. 开发环境和框架:Qt Creator + Qt 5.6(MinGW4.9), [下载地址](http://download.qt.io/official_releases/qt/5.6/5.6.0/qt-opensource-windows-x86-android-5.6.0.exe) 59 | 安装时勾选Tools/MinGW4.9 60 | 61 | 5. 网络编程主要使用POCO C++ Library实现, [官方文档](http://pocoproject.org/docs/Poco.Net.MailMessage.html) 62 | 63 | 6. 前端主要使用qml-material扩展模块实现, [官方文档](http://papyros.io/qml-material/) 64 | 65 | 下载地址: box提取码 material 66 | 67 | 配置说明: http://www.heilqt.com/topic/56b010459e5a7aac4bc63b42 68 | 69 | 70 | --------- -------------------------------------------------------------------------------- /qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | MyButton.qml 5 | AccountLogin.qml 6 | NewMailEdit.qml 7 | MailView.qml 8 | 9 | 10 | icons/add.svg 11 | icons/menu.svg 12 | icons/person.svg 13 | icons/person_add.svg 14 | icons/refresh.svg 15 | icons/search.svg 16 | icons/select_all.svg 17 | icons/add_box.svg 18 | icons/add_circle.svg 19 | icons/add_circle_outline.svg 20 | icons/archive.svg 21 | icons/backspace.svg 22 | icons/block.svg 23 | icons/clear.svg 24 | icons/content_copy.svg 25 | icons/content_cut.svg 26 | icons/content_paste.svg 27 | icons/create.svg 28 | icons/drafts.svg 29 | icons/filter_list.svg 30 | icons/flag.svg 31 | icons/font_download.svg 32 | icons/forward.svg 33 | icons/gesture.svg 34 | icons/inbox.svg 35 | icons/link.svg 36 | icons/mail.svg 37 | icons/markunread.svg 38 | icons/move_to_inbox.svg 39 | icons/next_week.svg 40 | icons/redo.svg 41 | icons/remove.svg 42 | icons/remove_circle.svg 43 | icons/remove_circle_outline.svg 44 | icons/reply.svg 45 | icons/reply_all.svg 46 | icons/report.svg 47 | icons/save.svg 48 | icons/send.svg 49 | icons/sort.svg 50 | icons/text_format.svg 51 | icons/unarchive.svg 52 | icons/undo.svg 53 | icons/weekend.svg 54 | icons/folder.svg 55 | icons/folder_open.svg 56 | 57 | 58 | -------------------------------------------------------------------------------- /Model/Account.h: -------------------------------------------------------------------------------- 1 | #ifndef ACCOUNT_H 2 | #define ACCOUNT_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | class Account: public QObject 14 | { 15 | Q_OBJECT 16 | 17 | Q_PROPERTY(QString username READ getUserName WRITE setUserName) 18 | 19 | Q_PROPERTY(QString password READ getPassWord WRITE setPassWord) 20 | 21 | Q_PROPERTY(QString mailhost READ getMailHost WRITE setMailHost) 22 | 23 | Q_PROPERTY(QString smtphost READ getSMTPHost WRITE setSMTPHost) 24 | 25 | Q_PROPERTY(QString pop3host READ getPOP3Host WRITE setPOP3Host) 26 | 27 | Q_PROPERTY(QString imaphost READ getIMAPHost WRITE setIMAPHost) 28 | 29 | Q_PROPERTY(bool requiressl READ getRequireSSL WRITE setRequireSSL) 30 | 31 | QString _userName; 32 | QString _passWord; 33 | QString _mailHost; 34 | QString _smtpHost; 35 | QString _pop3Host; 36 | QString _imapHost; 37 | bool _requireSSL; 38 | QStringList _contacts; 39 | 40 | 41 | 42 | public: 43 | Account() {} 44 | 45 | Account(QString un, QString pw) { 46 | _userName = un; 47 | _passWord = pw; 48 | } 49 | 50 | void AddContact(QString c) { 51 | _contacts.push_back(c); 52 | } 53 | 54 | QString getUserName() const { 55 | return _userName; 56 | } 57 | 58 | void setUserName(QString s) { 59 | _userName = s; 60 | } 61 | 62 | QString getPassWord() const { 63 | return _passWord; 64 | } 65 | 66 | void setPassWord(QString s) { 67 | _passWord = s; 68 | } 69 | 70 | QString getMailHost() const { 71 | return _mailHost; 72 | } 73 | 74 | void setMailHost(QString s) { 75 | _mailHost = s; 76 | } 77 | 78 | QString getSMTPHost() const { 79 | return _smtpHost; 80 | } 81 | 82 | void setSMTPHost(QString s) { 83 | _smtpHost = s; 84 | } 85 | 86 | QString getPOP3Host() const { 87 | return _pop3Host; 88 | } 89 | 90 | void setPOP3Host(QString s) { 91 | _pop3Host = s; 92 | } 93 | 94 | QString getIMAPHost() const { 95 | return _imapHost; 96 | } 97 | 98 | void setIMAPHost(QString s) { 99 | _imapHost = s; 100 | } 101 | 102 | bool getRequireSSL() const { 103 | return _requireSSL; 104 | } 105 | 106 | void setRequireSSL(bool i) { 107 | _requireSSL = i; 108 | } 109 | 110 | QStringList getContacts() const { 111 | return _contacts; 112 | } 113 | 114 | 115 | }; 116 | 117 | 118 | typedef QSharedPointer ACCOUNT_PTR; 119 | typedef QList ACCOUNT_PTR_QLIST; 120 | 121 | 122 | 123 | #endif // ACCOUNT_H 124 | 125 | 126 | -------------------------------------------------------------------------------- /Model/MailBody.h: -------------------------------------------------------------------------------- 1 | #ifndef MAILBODY_H 2 | #define MAILBODY_H 3 | 4 | #include "Attachment.h" 5 | #include "Account.h" 6 | #include "Exception/MailReceiveException.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | 17 | using namespace std; 18 | 19 | class MailBody : public QObject { 20 | private: 21 | Q_OBJECT 22 | 23 | Q_PROPERTY(QString subject READ getSubject CONSTANT) 24 | 25 | Q_PROPERTY(QString content READ getContent CONSTANT) 26 | 27 | Q_PROPERTY(QString sender READ getSender CONSTANT) 28 | 29 | Q_PROPERTY(QString datetime READ getDateTime CONSTANT) 30 | 31 | Q_PROPERTY(bool isread READ getIsread WRITE setIsread CONSTANT) 32 | 33 | // Q_PROPERTY(QList recipients READ getRecipient CONSTANT) 34 | 35 | 36 | public: 37 | 38 | MailBody(QString _s = "subject", QString _c="content", bool _r = false ){ 39 | _subject = _s; 40 | _content = _c; 41 | _isread = _r; 42 | } 43 | 44 | QString getSubject(){ 45 | return _subject; 46 | } 47 | 48 | void setSubject(QString s){ 49 | _subject = s; 50 | } 51 | 52 | QString getContent(){ 53 | return _content; 54 | } 55 | 56 | QString getHTMLContent(){ 57 | if( _htmlContent.length () > 0 ) 58 | return _htmlContent; 59 | else 60 | return _content; 61 | } 62 | 63 | void setHTMLContent (QString c){ 64 | _htmlContent = c; 65 | } 66 | 67 | void setContent(QString c){ 68 | _content = c; 69 | } 70 | 71 | QString getSender(){ 72 | return _sender; 73 | } 74 | 75 | void setSender(QString s){ 76 | _sender = s; 77 | } 78 | 79 | QString getDateTime(){ 80 | return _datetime; 81 | } 82 | 83 | void setDateTime(QString val){ 84 | _datetime = val; 85 | // _datetime = QDateTime::fromString (val, Qt::RFC2822Date); 86 | } 87 | 88 | bool getIsread(){ 89 | return _isread; 90 | } 91 | 92 | void setIsread(bool val){ 93 | _isread = val; 94 | } 95 | 96 | QList getRecipients(){ 97 | return _recipients; 98 | } 99 | 100 | void addRecipient(QString r) { 101 | _recipients.push_back (r); 102 | } 103 | 104 | QList getAttachements(){ 105 | return _attachements; 106 | } 107 | 108 | Attachment getAttachment(int index){ 109 | if( index >= 0 && index < _attachements.size () ) 110 | return _attachements.at (index); 111 | else 112 | throw MailReceiveException("Attachment Index Invalid"); 113 | return nullptr; 114 | } 115 | 116 | void addAttachment(const Attachment & attach){ 117 | _attachements.append (attach); 118 | } 119 | 120 | private: 121 | 122 | QString _subject; 123 | 124 | QString _content; 125 | 126 | QString _htmlContent; 127 | 128 | QString _sender; 129 | 130 | QString _datetime; 131 | 132 | QList _recipients; 133 | 134 | bool _isread; 135 | 136 | QList _attachements; 137 | 138 | }; 139 | 140 | typedef QSharedPointer MAILBODY_PTR; 141 | typedef QList MAILBODY_PTR_QLIST; 142 | 143 | 144 | 145 | #endif // MAILBODY_H 146 | -------------------------------------------------------------------------------- /Model/SMTPClient.h: -------------------------------------------------------------------------------- 1 | #ifndef SMTPCLIENT_H 2 | #define SMTPCLIENT_H 3 | 4 | #include "Account.h" 5 | #include "SendMailClient.h" 6 | #include "MailBody.h" 7 | #include "Attachment.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | class SMTPClient:public SendMailClient{ 26 | 27 | private: 28 | typedef QSharedPointer SESSION_PTR; 29 | 30 | public: 31 | SMTPClient(QString host, 32 | QString port = QString::number (Poco::Net::SMTPClientSession::SMTP_PORT)){ 33 | this->_session = SESSION_PTR::create(host.toStdString ()); 34 | this->_host = host; 35 | this->_port = port; 36 | } 37 | bool login(QString _user, QString _passwd,bool requireSSL) override{ 38 | try{ 39 | _session->login(Poco::Net::SMTPClientSession::AUTH_LOGIN,_user.toStdString (), _passwd.toStdString ()); 40 | return true; 41 | } 42 | catch(Poco::Net::SMTPException & e){ 43 | return false; 44 | } 45 | } 46 | 47 | bool sendMailBodies(const MAILBODY_PTR & MailBody) override{ 48 | // MAILBODY_PTR newMail = MAILBODY_PTR::create(); 49 | Poco::Net::MailMessage newMail; 50 | Poco::Net::MediaType type("multipart", "related"); 51 | 52 | type.setParameter ("type","text/html"); 53 | newMail.setSender(MailBody->getSender().toStdString()); 54 | 55 | auto list = MailBody->getRecipients(); 56 | 57 | for (auto i = list.begin(); i != list.end(); i++){ 58 | std::cout << i->toStdString () << std::endl; 59 | Poco::Net::MailRecipient mailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, i->toStdString()); 60 | newMail.addRecipient(mailRecipient); 61 | } 62 | 63 | newMail.setSubject(MailBody->getSubject().toStdString()); 64 | 65 | newMail.setContentType (type); 66 | 67 | newMail.addPart ("", new Poco::Net::StringPartSource(MailBody->getHTMLContent().toStdString(), "text/html"), Poco::Net::MailMessage::CONTENT_INLINE, Poco::Net::MailMessage::ENCODING_QUOTED_PRINTABLE); 68 | 69 | for(auto attach: MailBody->getAttachements ()){ 70 | newMail.addAttachment (attach.getFileName ().toStdString (), new Poco::Net::FilePartSource(attach.getFilePath ().toStdString ())); 71 | } 72 | 73 | // newMail->setHTMLContent(MailBody->getHTMLContent()); 74 | 75 | newMail.setDate(Poco::Timestamp::fromEpochTime( QDateTime::fromString(MailBody->getDateTime()).toTime_t())); 76 | 77 | try{ 78 | _session->sendMessage(newMail); 79 | return true; 80 | qDebug() <<"Message successfully sent\n" ; 81 | } 82 | catch(Poco::Net::SMTPException &e){ 83 | std::cout << e.what () << std::endl; 84 | return false; 85 | } 86 | } 87 | void setTimeout(int val)override{ 88 | Poco::Timespan timeout = Poco::Timespan(0,0,0,0,1000 * val); //该构造函数默认最小是微妙(第五个参数),前四个:day,hour,minute,second,这里的延时我们需要以毫秒计 89 | _session->setTimeout(timeout); 90 | } 91 | int getTimeout ()override{ 92 | return _session->getTimeout().milliseconds(); 93 | } 94 | ~SMTPClient(){ 95 | 96 | } 97 | 98 | private: 99 | SESSION_PTR _session; 100 | }; 101 | 102 | #endif // SMTPCLIENT_H 103 | -------------------------------------------------------------------------------- /AccountLogin.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.6 2 | import QtQuick.Window 2.2 3 | import QtQuick.Layouts 1.1 4 | import Material 0.2 5 | import Material.ListItems 0.1 as ListItem 6 | 7 | 8 | Dialog { 9 | id: loginWindow 10 | 11 | title: "Account Login" 12 | 13 | visible: true 14 | 15 | width: Units.dp(350) 16 | 17 | height: column.implicitHeight + Units.dp(120) 18 | 19 | hasActions: false 20 | 21 | property alias signInButton : signInButton 22 | 23 | property alias cancelButton: cancelButton 24 | 25 | property alias addressText: addressTextField.text 26 | 27 | property alias passwordText: pwdField.text 28 | 29 | property alias selectedProtocol: protocolMenu.selectedText 30 | 31 | property alias sendHost: sendHostText.text 32 | 33 | property alias receiveHost: receiveHostText.text 34 | 35 | property alias requireSSL: requireSSLSwitch.checked 36 | 37 | property var receiveProtocol: [ "IMAP", "POP3" ] 38 | 39 | ColumnLayout { 40 | id: column 41 | 42 | spacing: Units.dp(10) 43 | 44 | anchors { 45 | fill: parent 46 | topMargin: Units.dp(16) 47 | bottomMargin: Units.dp(16) 48 | } 49 | 50 | Item { 51 | Layout.fillWidth: true 52 | Layout.preferredHeight: Units.dp(8) 53 | } 54 | 55 | ListItem.Standard { 56 | action: Icon { 57 | anchors.centerIn: parent 58 | name: "communication/email" 59 | } 60 | 61 | content: TextField { 62 | anchors.centerIn: parent 63 | width: parent.width 64 | id: addressTextField 65 | text: "375670450@qq.com" 66 | } 67 | } 68 | 69 | ListItem.Standard { 70 | action: Icon { 71 | anchors.centerIn: parent 72 | name: "communication/vpn_key" 73 | } 74 | 75 | content: TextField { 76 | id: pwdField 77 | anchors.centerIn: parent 78 | width: parent.width 79 | echoMode: TextInput.Password 80 | text: "sftkpahwbroabhjg" 81 | } 82 | } 83 | 84 | 85 | 86 | ListItem.Standard { 87 | 88 | Layout.preferredHeight: Units.dp(30) 89 | 90 | content: RowLayout { 91 | anchors.centerIn: parent 92 | width: parent.width 93 | 94 | Label { 95 | Layout.alignment: Qt.AlignVCenter 96 | Layout.preferredWidth: 0.3 * parent.width 97 | text: "SMTP" 98 | } 99 | 100 | TextField { 101 | id: sendHostText 102 | anchors.bottom: parent.bottom 103 | Layout.fillWidth: true 104 | placeholderText: "smtp.qq.com" 105 | text: "smtp.qq.com" 106 | } 107 | 108 | } 109 | } 110 | 111 | ListItem.Standard { 112 | 113 | Layout.preferredHeight: Units.dp(30) 114 | 115 | content: RowLayout { 116 | anchors.centerIn: parent 117 | width: parent.width 118 | 119 | MenuField { 120 | id: protocolMenu 121 | Layout.alignment: Qt.AlignVCenter 122 | Layout.preferredWidth: 0.3 * parent.width 123 | model: receiveProtocol 124 | } 125 | 126 | TextField { 127 | id: receiveHostText 128 | anchors.bottom: parent.bottom 129 | anchors.bottomMargin: Units.dp(15) 130 | Layout.fillWidth: true 131 | placeholderText: "imap.qq.com" 132 | text: "imap.qq.com" 133 | } 134 | 135 | } 136 | } 137 | 138 | RowLayout{ 139 | // anchors.horizontalCenter: parent.horizontalCenter 140 | 141 | spacing: Units.dp(30) 142 | 143 | Label{ 144 | text: "Require SSL" 145 | } 146 | 147 | Switch{ 148 | id: requireSSLSwitch 149 | Layout.alignment: Qt.AlignHCenter 150 | onClicked: { 151 | requireSSL = !requireSSL 152 | console.log("require ssl = " + requireSSL) 153 | } 154 | checked: true 155 | } 156 | 157 | } 158 | 159 | Item { 160 | Layout.fillWidth: true 161 | Layout.preferredHeight: Units.dp(8) 162 | } 163 | 164 | RowLayout { 165 | 166 | Layout.alignment: Qt.AlignHCenter 167 | spacing: Units.dp(8) 168 | 169 | Button { 170 | id: cancelButton 171 | text: "Cancel" 172 | textColor: Theme.primaryColor 173 | onClicked: close() 174 | } 175 | 176 | Button { 177 | id: signInButton 178 | text: "Login" 179 | textColor: Theme.primaryColor 180 | } 181 | } 182 | } 183 | 184 | 185 | } 186 | -------------------------------------------------------------------------------- /Model/Attachment.h: -------------------------------------------------------------------------------- 1 | #ifndef ATTACHMENT_H 2 | #define ATTACHMENT_H 3 | #include "Utils.h" 4 | #include "Exception/MailClientException.h" 5 | #include "Exception/MailGenerationException.h" 6 | 7 | #include "Poco/Net/PartSource.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | using namespace std; 20 | 21 | class Attachment : public Poco::Net::PartSource 22 | { 23 | private: 24 | typedef enum{unDownloaded, isDownloading, isDownloaded} downloadState; 25 | 26 | Utils::MediaType _attachmentType; 27 | qint64 _fileSize; 28 | qint64 _hasDownloaded; 29 | 30 | QString _fileName; 31 | QString _filePath; 32 | downloadState _state; 33 | QString _accessCommand; 34 | 35 | fstream _fileStream; 36 | 37 | const static qint64 _fileMaxSize = 1024*1024; 38 | 39 | int findPostfix(const QString &src) { 40 | int i = src.length() - 1; 41 | while(src[i]!='.') i--; 42 | return i; 43 | } 44 | 45 | public: 46 | 47 | std::istream& stream() override { 48 | return _fileStream; 49 | } 50 | 51 | Attachment(const std::string& mediaType): 52 | _attachmentType(mediaType) { 53 | _state = unDownloaded; 54 | _hasDownloaded = 0; 55 | } 56 | 57 | Attachment(const std::string& type, const std::string& subType): 58 | _attachmentType(type, subType) { 59 | _state = unDownloaded; 60 | _hasDownloaded = 0; 61 | } 62 | 63 | Attachment(const Utils::MediaType& mediaType): 64 | _attachmentType(mediaType) { 65 | _state = unDownloaded; 66 | _hasDownloaded = 0; 67 | } 68 | 69 | Attachment(const Attachment & attach): 70 | _attachmentType(attach.getAttachmentType ()){ 71 | _fileSize = attach._fileSize; 72 | _hasDownloaded = attach._hasDownloaded; 73 | 74 | _fileName = attach._fileName; 75 | _filePath = attach._filePath; 76 | _state = attach._state; 77 | _accessCommand = attach._accessCommand; 78 | } 79 | 80 | Utils::MediaType getAttachmentType() const { 81 | return _attachmentType; 82 | } 83 | 84 | size_t getFileSize() const { 85 | return _fileSize; 86 | } 87 | 88 | void setFileSize(size_t i) { 89 | _fileSize = i; 90 | } 91 | 92 | QString getFileName() const { 93 | if( _fileName.length () > 0 ) 94 | return _fileName; 95 | else if ( _filePath.length () > 0 ) 96 | return QString::fromStdString (_filePath.toStdString ().substr ( _filePath.lastIndexOf ('.'))); 97 | } 98 | 99 | void setFileName(const QString& i) { 100 | QString val; 101 | for(auto it = i.begin (); it != i.end (); it++){ 102 | if( it->isPrint () ) 103 | val += *it; 104 | } 105 | _fileName = val; 106 | } 107 | 108 | QString getFilePath() const { 109 | return _filePath; 110 | } 111 | 112 | void setFilePath(const QString& i) { 113 | _filePath = i; 114 | _fileStream.open(_filePath.toStdString(), ios::in|ios::out|ios::binary); 115 | } 116 | 117 | QString getAccessCommand() const { 118 | return _accessCommand; 119 | } 120 | 121 | void setAccessCommand(const QString& i) { 122 | _accessCommand = i; 123 | } 124 | 125 | bool Download(const QByteArray& data) { 126 | 127 | QString tmp = _filePath; 128 | int t = findPostfix(tmp); 129 | QString postfix = tmp.mid(t, tmp.length()-t); 130 | tmp = tmp.mid(0,t); 131 | if(_state == unDownloaded) { //make sure the file name is not existed 132 | for(int i = 1; QFile::exists(_filePath); i++) { 133 | _filePath = tmp + "("; 134 | _filePath += i + '0'; 135 | _filePath += ")"; 136 | _filePath += postfix; 137 | } 138 | _state = isDownloading; 139 | } 140 | 141 | QFile output(_filePath); 142 | output.open(QIODevice::WriteOnly|QIODevice::Append); 143 | qint64 size = data.size(); 144 | output.write(data.data(), size); 145 | output.close(); 146 | 147 | _hasDownloaded += size; 148 | if(_hasDownloaded == _fileSize) 149 | _state = isDownloaded; 150 | return true; 151 | } 152 | 153 | bool Upload(QByteArray& data) { 154 | QFile input(_filePath); 155 | 156 | try { 157 | if(input.isOpen()) 158 | throw(MailGenerationException("File is being occupied!")); 159 | if(!input.open(QIODevice::ReadOnly)) //file not existed 160 | throw(MailGenerationException("File doesn't exists!")); 161 | qint64 size = input.size(); 162 | if(size > _fileMaxSize) 163 | throw(MailGenerationException("File size is beyond limit!")); 164 | } catch(MailGenerationException& mse) { 165 | qDebug() << mse.what() << endl; 166 | return false; 167 | } 168 | 169 | data = input.readAll(); 170 | 171 | input.close(); 172 | return true; 173 | } 174 | 175 | }; 176 | 177 | typedef QSharedPointer ATTACHMENT_PTR; 178 | 179 | #endif // ATTACHMENT_H 180 | -------------------------------------------------------------------------------- /MailView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.6 2 | import QtQuick.Window 2.2 3 | import QtQuick.Controls 1.1 4 | import QtQuick.Layouts 1.1 5 | import Material 0.2 6 | import Material.Extras 0.1 7 | import Material.ListItems 0.1 as ListItem 8 | import QtWebEngine 1.2 9 | 10 | 11 | Item{ 12 | 13 | id: mailView 14 | 15 | // visible: selectedMailIndex >= 0 16 | 17 | visible: true 18 | 19 | property string attachmentColor: Palette.colors["blue"]["200"] 20 | 21 | // property alias unreadButton: markAsUnreadButton 22 | 23 | // property alias replyButton: replyButton 24 | 25 | function loadHtml(content){ 26 | mailWebView.loadHtml(content) 27 | console.log("in function loadHtml:"+content ) 28 | } 29 | 30 | ColumnLayout{ 31 | 32 | 33 | spacing: Units.dp(8) 34 | 35 | anchors.fill: parent 36 | anchors.margins: Units.dp(10) 37 | anchors.topMargin: 0 38 | 39 | RowLayout{ 40 | id : mailViewToolBar 41 | 42 | height: Units.dp(60) 43 | 44 | spacing: 0 45 | 46 | anchors.top : parent.top 47 | 48 | anchors.right: parent.right 49 | 50 | Layout.fillWidth : true 51 | 52 | MyButton{ 53 | id : markAsUnreadButton 54 | label : "Mark As Unread" 55 | source: "/icons/mail_unread" 56 | Layout.preferredWidth: Units.dp(label.length*8 + 60) 57 | } 58 | 59 | MyButton{ 60 | id : replyButton 61 | label: "Reply" 62 | source: "/icons/reply" 63 | Layout.preferredWidth: Units.dp(label.length*8 + 60) 64 | onClicked: pageLoader.newMail() 65 | 66 | } 67 | 68 | MyButton{ 69 | id : replyAllButton 70 | label: "Reply All" 71 | source: "/icons/reply_all" 72 | Layout.preferredWidth: Units.dp(label.length*8 + 60) 73 | } 74 | 75 | } 76 | 77 | ProgressBar{ 78 | Layout.fillWidth: true 79 | value: mailWebView.loadProgress/100.0 80 | } 81 | 82 | RowLayout{ 83 | id: mailHeaderView 84 | 85 | height: mailViewToolBar.height 86 | 87 | spacing: Units.dp(10) 88 | 89 | Rectangle{ 90 | height: parent.height / 2 91 | width: height 92 | radius: height/2 93 | color: theme.accentColor 94 | Label{ 95 | anchors.centerIn: parent 96 | text: mailHeaderSender.text.charAt(0) 97 | } 98 | } 99 | 100 | ColumnLayout{ 101 | spacing: Units.dp(2) 102 | Label { 103 | id : mailHeaderSender 104 | text : mailListModel.getSender(selectedMailIndex) 105 | font.bold: true 106 | font.pixelSize: Units.dp(20) 107 | } 108 | 109 | Label { 110 | id : mailHeaderDatetime 111 | text : mailListModel.getDateTime(selectedMailIndex) 112 | font.pixelSize: Units.dp(13) 113 | 114 | } 115 | } 116 | 117 | } 118 | 119 | Label { 120 | text : mailListModel.getSubject(selectedMailIndex); 121 | } 122 | 123 | Label{ 124 | text : mailListModel.getRecipients(selectedMailIndex); 125 | } 126 | 127 | RowLayout{ 128 | 129 | id: attachmentsRow 130 | 131 | Layout.fillWidth: true 132 | 133 | height: Units.dp(50) 134 | 135 | visible: attachmentsRepeater.count > 0 136 | 137 | Repeater{ 138 | id: attachmentsRepeater 139 | 140 | model: mailListModel.getAttachments(selectedMailIndex) 141 | 142 | delegate: Component{ 143 | 144 | MyButton{ 145 | source: "/icons/file" 146 | 147 | backgroundColor: attachmentColor 148 | 149 | height: parent.height 150 | 151 | label: model.modelData 152 | 153 | onClicked: { 154 | mailListModel.downloadAttach(selectedMailIndex, index, "."); 155 | // console.log( "selectedMailIndex" + selectedMailIndex ) 156 | // console.log(" index" + index) 157 | } 158 | } 159 | 160 | } 161 | } 162 | } 163 | 164 | WebEngineView{ 165 | 166 | id: mailWebView 167 | 168 | Layout.fillHeight: true 169 | Layout.fillWidth: true 170 | url: "https://www.baidu.com/" 171 | // url: "" 172 | onLoadProgressChanged: console.log(mailWebView.loadProgress) 173 | 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /Model/IMAPClient.h: -------------------------------------------------------------------------------- 1 | #ifndef IMAPCLIENT_H 2 | #define IMAPCLIENT_H 3 | 4 | #include "Account.h" 5 | #include "ReceiveMailClient.h" 6 | #include "IMAPClientSession.h" 7 | #include "MailBody.h" 8 | #include "Attachment.h" 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | typedef std::vector FolderInfoVec; 21 | 22 | class IMAPClient : public ReceiveMailClient 23 | { 24 | private: 25 | typedef QSharedPointer SESSION_PTR; 26 | 27 | public: 28 | 29 | IMAPClient(QString host, 30 | QString port = QString::number (Poco::Net::IMAPClientSession::IMAP_PORT)) { 31 | this->_session = SESSION_PTR::create(host.toStdString ()); 32 | this->_host = host; 33 | this->_port = port; 34 | } 35 | 36 | bool login(QString _user, QString _passwd, bool p) override{ 37 | try{ 38 | _session->login(_user.toStdString (), _passwd.toStdString ()); 39 | 40 | return true; 41 | } 42 | catch(Poco::Net::IMAPException & e){ 43 | return false; 44 | } 45 | 46 | } 47 | 48 | int getFolders(QList & _folders) override{ 49 | 50 | FolderInfoVec folders; 51 | 52 | _session->listFolders("", folders); // root is null 53 | 54 | for(auto f : folders){ 55 | _folders.push_back (QString::fromStdString (f.name.c_str())); 56 | } 57 | 58 | return folders.size (); 59 | } 60 | 61 | int selectFolder(const QString & folder) override{ 62 | 63 | _mailList.clear (); 64 | 65 | std::vector uids; 66 | 67 | _selectedFolder = folder; 68 | 69 | _session->listMessages (folder.toStdString (), uids); 70 | 71 | _session->getMessages (folder.toStdString (), uids, _mailList); 72 | 73 | qDebug() << "In select Folder, folder = "<< folder << ", mailList.size = " << _mailList.size () << "uids.size = " << uids.size ()<< "\n"; 74 | 75 | for(int i=0; i<_mailList.size (); i++){ 76 | for(int j=0; jloadPartData (info.uid, info.parts, tokens[1].toStdString(), data); 97 | outdata = data; 98 | return 1; 99 | } 100 | 101 | catch( const std::exception & e ){ 102 | qDebug() << "Unable to get attachment, exception:" << e.what () << "\n"; 103 | return 0; 104 | } 105 | } 106 | 107 | int getMailBodies(QList & result, int count ) override{ 108 | 109 | std::map paths; 110 | 111 | int counter = 0; 112 | 113 | for( ; _curListIndex < _mailList.size (); _curListIndex++, counter++) { 114 | 115 | if( counter >= count ) 116 | break; 117 | 118 | int actualIndex = _mailList.size () - _curListIndex - 1; 119 | 120 | auto info = _mailList.at ( actualIndex ); 121 | 122 | _session->loadMessage (_selectedFolder.toStdString (), info, paths); 123 | 124 | MAILBODY_PTR newmail = MAILBODY_PTR::create(QString::fromStdString (info.subject.c_str ())); 125 | 126 | for( auto it = paths.begin (); it != paths.end (); it++){ 127 | 128 | auto partInfo = info.parts.childs[std::atoi(it->second.c_str())]; 129 | 130 | if( partInfo.attributes[0] == "BOUNDARY" ) 131 | break; 132 | 133 | Attachment attach(partInfo.attributes[0],partInfo.attributes[1]); 134 | 135 | attach.setFileName (QString::fromStdString (it->first)); 136 | 137 | attach.setFileSize ( std::atoi (partInfo.attributes[5].c_str())); 138 | 139 | std::stringstream ss; 140 | ss << actualIndex << ";" << it->second; 141 | 142 | attach.setAccessCommand ( QString::fromStdString ( ss.str () ) ); 143 | 144 | 145 | // qDebug() << actualIndex << " || " << QString::fromStdString(it->second ) << " ||\n"; 146 | qDebug() << QString::fromStdString ( ss.str () ) << "\n"; 147 | 148 | newmail->addAttachment (attach); 149 | } 150 | 151 | 152 | newmail->setContent (QString::fromStdString (info.text.c_str ())); 153 | 154 | newmail->setHTMLContent (QString::fromStdString (info.htmlText.c_str ())); 155 | 156 | // qDebug() << QString::fromStdString ( info.uid.c_str() ) << " content: " << newmail->getHTMLContent ()<< "\n"; 157 | 158 | std::string sender = info.from.find_last_of('<') != std::string::npos ? 159 | info.from.substr(info.from.find_last_of('<')+1, info.from.find_last_of('>') - info.from.find_last_of('<')-1) : 160 | info.from ; 161 | 162 | newmail->setSender (QString::fromStdString (sender.c_str())); 163 | 164 | newmail->addRecipient (QString::fromStdString (info.to.c_str())); 165 | 166 | newmail->setDateTime (QString::fromStdString (info.date.c_str())); 167 | 168 | newmail->setIsread (false); 169 | 170 | result.push_back (newmail); 171 | } 172 | 173 | return counter; 174 | 175 | } 176 | 177 | int getAttachment(){ 178 | 179 | } 180 | 181 | int DeleteMail (const QList & ids) override{ 182 | return 0; 183 | } 184 | 185 | void setTimeout (int val) override{ 186 | _session->socket ().setReceiveTimeout (val); 187 | _session->socket ().setSendTimeout (val); 188 | } 189 | 190 | int getTimeout () override{ 191 | return _session->socket ().getReceiveTimeout ().totalMilliseconds (); 192 | } 193 | 194 | ~IMAPClient(){ 195 | 196 | } 197 | 198 | private: 199 | 200 | Poco::Net::IMAPClientSession::MessageInfoVec _mailList; 201 | 202 | SESSION_PTR _session; 203 | 204 | }; 205 | 206 | #endif // IMAPCLIENT_H 207 | -------------------------------------------------------------------------------- /main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.6 2 | import QtQuick.Window 2.2 3 | import QtQuick.Controls 1.1 4 | import QtQuick.Layouts 1.1 5 | import Material 0.2 6 | import Material.Extras 0.1 7 | import Material.ListItems 0.1 as ListItem 8 | import QtWebEngine 1.2 9 | 10 | ApplicationWindow { 11 | id : mainWindow 12 | 13 | title: "MicroMailClient" 14 | 15 | visible: true 16 | 17 | property bool isLargeWindow: width > Screen.desktopAvailableWidth/2 18 | 19 | property int selectedMailIndex: -1 20 | 21 | property int selectedFolder: 0 22 | 23 | property string globalBackgroundColor: "whitesmoke" 24 | 25 | property string sidebarColor: Palette.colors["blue"]["200"] 26 | 27 | property double iconScale: 0.8 28 | 29 | property string contentFont: "微软雅黑" 30 | 31 | property string receiveHost : "pop.qq.com"; 32 | 33 | property string sendHost: "smtp.qq.com"; 34 | 35 | property string user : ""; 36 | 37 | property string passwd : ""; 38 | 39 | property bool requireSSL: false 40 | 41 | property var uploadAttach: [] 42 | 43 | theme { 44 | primaryColor: "blue" 45 | accentColor: "red" 46 | primaryDarkColor: "gray" 47 | tabHighlightColor: "Zwhite" 48 | } 49 | 50 | initialPage: Tab{ 51 | sourceComponent: mainWindowComponent 52 | 53 | } 54 | 55 | Component{ 56 | id: mainWindowComponent 57 | 58 | Rectangle{ 59 | 60 | id: backgroundRectangle 61 | 62 | color: Theme.backgroundColor 63 | 64 | anchors.fill: parent 65 | 66 | MouseArea{ 67 | 68 | anchors.fill: parent 69 | property variant previousPosition 70 | onPressed: { 71 | previousPosition = Qt.point(mouseX, mouseY) 72 | } 73 | onPositionChanged: { 74 | if( pressedButtons == Qt.LeftButton ){ 75 | mainWindow.x += mouseX - previousPosition.x 76 | mainWindow.y += mouseY - previousPosition.y 77 | } 78 | } 79 | onClicked: { 80 | menuSidebar.expanded = false 81 | } 82 | } 83 | 84 | Sidebar{ 85 | id: menuSidebar // 完整的侧边栏 86 | expanded: true 87 | width: Units.dp(200) 88 | 89 | backgroundColor: sidebarColor 90 | 91 | ColumnLayout{ 92 | anchors.fill: parent 93 | spacing: Units.dp(2) 94 | 95 | width: parent.width 96 | 97 | Button{ 98 | width: height * 1.2 99 | Image { 100 | source: "/icons/menu" 101 | scale: iconScale 102 | } 103 | onClicked: menuSidebar.expanded = !menuSidebar.expanded 104 | } 105 | 106 | MyButton{ 107 | id: newMailButton 108 | Layout.fillWidth: true 109 | source: "/icons/add" 110 | label: "New Mail" 111 | 112 | onClicked: { 113 | pageLoader.newMail() 114 | } 115 | 116 | } 117 | 118 | MyButton{ 119 | Layout.fillWidth: true 120 | source: "/icons/person" 121 | label: "Accounts" 122 | 123 | } 124 | 125 | MyButton{ 126 | Layout.fillWidth: true 127 | source: "/icons/person_add" 128 | label: "Add Account" 129 | 130 | onClicked: { 131 | loginDialog.visible = true 132 | loginDialog.show() 133 | } 134 | 135 | } 136 | 137 | ListItem.SectionHeader{ 138 | id: foldersSectionHeader 139 | 140 | Layout.fillWidth: true 141 | 142 | RowLayout{ 143 | 144 | Image { 145 | id: foldersImage 146 | scale: iconScale 147 | } 148 | 149 | Label{ 150 | anchors.verticalCenter: parent.verticalCenter 151 | text: "Folders" 152 | } 153 | 154 | } 155 | 156 | state: "open" 157 | expanded: true 158 | 159 | states:[ 160 | State{ 161 | name: "open" 162 | PropertyChanges { 163 | target: foldersImage 164 | source: "/icons/folder_open" 165 | } 166 | }, 167 | 168 | State{ 169 | name: "close" 170 | PropertyChanges { 171 | target: foldersImage 172 | source: "/icons/folder" 173 | } 174 | } 175 | 176 | ] 177 | 178 | onClicked: { 179 | state == "close" ? state = "open" : state = "close"; 180 | 181 | } 182 | 183 | } 184 | 185 | ColumnLayout { 186 | anchors.top: foldersSectionHeader.bottom 187 | width: foldersSectionHeader.width 188 | 189 | Repeater{ 190 | id: foldersList 191 | 192 | model: mailListModel.folders 193 | // model: temp 194 | Layout.fillWidth: true 195 | delegate: foldersListDelegate 196 | // onModelChanged: console.log("model = " + model) 197 | } 198 | 199 | } 200 | 201 | Component{ 202 | id: foldersListDelegate 203 | ListItem.Standard{ 204 | width: foldersSectionHeader.width 205 | visible: { foldersSectionHeader.expanded } 206 | 207 | // backgroundColor: mailListModel.folderIndex == index ? 208 | 209 | 210 | Label{ 211 | text: model.modelData 212 | anchors.verticalCenter: parent.verticalCenter 213 | anchors.left: parent.left 214 | anchors.leftMargin: Units.dp(10) 215 | font.pixelSize: Units.dp(13) 216 | } 217 | onVisibleChanged: console.log("listitem visible changed: " + visible) 218 | onClicked: mailListModel.buildMailList(index) 219 | } 220 | } 221 | 222 | } 223 | 224 | } 225 | 226 | Rectangle{ 227 | 228 | id: thinMenuSidebar // 小的侧边栏 229 | 230 | width: menuSidebar.expanded ? 0 : Units.dp(35) 231 | 232 | height: parent.height 233 | 234 | color: sidebarColor 235 | 236 | anchors.left: menuSidebar.right 237 | 238 | Column { 239 | spacing: Units.dp(10) 240 | 241 | anchors.fill : parent 242 | 243 | Button{ 244 | 245 | width: parent.width 246 | height: width 247 | Image{ 248 | // scale: iconScale 249 | anchors.fill: parent 250 | source: "/icons/menu" 251 | } 252 | 253 | onClicked: { 254 | menuSidebar.expanded = !menuSidebar.expanded 255 | } 256 | } 257 | 258 | } 259 | 260 | } 261 | 262 | 263 | 264 | Rectangle{ 265 | 266 | id: mailListColumn 267 | 268 | anchors.left: thinMenuSidebar.right 269 | 270 | anchors.leftMargin: Units.dp(4) 271 | 272 | width: isLargeWindow ? Units.dp(400) : parent.width - thinMenuSidebar.width 273 | 274 | height: parent.height 275 | 276 | color: Theme.backgroundColor 277 | 278 | ListView{ 279 | 280 | id:mailListView 281 | 282 | anchors.fill: parent 283 | 284 | width: parent.width 285 | 286 | delegate:mailListDelegate 287 | 288 | Label { 289 | visible: mailListModel.progress === 0 290 | anchors.centerIn : parent 291 | text: "empty" 292 | font.pixelSize: Units.dp(20) 293 | } 294 | 295 | model: mailListModel 296 | 297 | header : Rectangle{ 298 | id: mailListHeader 299 | height: Units.dp(35) 300 | width: mailListView.width 301 | 302 | Rectangle{ 303 | id : searchTextRectangle 304 | height: mailListHeader.height 305 | width: parent.width - mailListHeaderButtonRectangle.width 306 | color: globalBackgroundColor 307 | border.color: searchTextField.activeFocus ? "lightgray" : color 308 | 309 | TextField{ 310 | 311 | id: searchTextField 312 | text: "search" 313 | height: mailListHeader.height 314 | anchors.right: searchButton.left 315 | width: parent.width - searchButton.width 316 | font.pointSize: Units.dp(14) 317 | font.bold: false 318 | font.family: contentFont 319 | 320 | } 321 | 322 | Button{ 323 | id : searchButton 324 | anchors.right: parent.right 325 | width: Units.dp(40) 326 | 327 | Image{ 328 | scale: iconScale 329 | id : searchButtonImage 330 | anchors.fill: parent 331 | anchors.margins: Units.dp(4) 332 | source: "/icons/search" 333 | 334 | } 335 | 336 | onClicked: { 337 | console.log("Search Button Clicked") 338 | } 339 | 340 | } 341 | 342 | } 343 | 344 | Rectangle{ 345 | id: mailListHeaderButtonRectangle 346 | anchors.left: searchTextRectangle.right 347 | height: mailListHeader.height 348 | width: Units.dp(80) 349 | 350 | color: globalBackgroundColor 351 | 352 | Button{ 353 | id: refreshButton 354 | width: parent.width/2 355 | Image{ 356 | scale: iconScale 357 | anchors.fill: parent 358 | anchors.margins: Units.dp(4) 359 | source: "/icons/refresh" 360 | } 361 | onClicked: { 362 | console.log("refresh button onclick") 363 | mailListModel.login(user, passwd, receiveHost, port) 364 | } 365 | 366 | } 367 | Button{ 368 | anchors.left: refreshButton.right 369 | id: selectButton 370 | 371 | width: parent.width/2 372 | Image{ 373 | scale: iconScale 374 | anchors.fill: parent 375 | anchors.margins: Units.dp(4) 376 | source: "/icons/select" 377 | } 378 | onClicked: { 379 | console.log("select button onclick") 380 | // alertNoTitleBar.show() 381 | } 382 | } 383 | } 384 | 385 | ProgressBar{ 386 | 387 | id: mailListProgressBar 388 | width: parent.width 389 | anchors.bottom : parent.bottom 390 | 391 | value: mailListModel.progress 392 | 393 | onValueChanged: { 394 | if( mailListProgressBar.value === 1 ){ 395 | snackbar.open("Load mails completely") 396 | } 397 | } 398 | 399 | } 400 | 401 | } 402 | 403 | section.property: "mail_datetime" // should be datetime 404 | section.criteria: ViewSection.FullString 405 | section.delegate: mailListSectionDelegate 406 | 407 | 408 | 409 | } 410 | 411 | /* 412 | Invisible Components of mailListColumn 413 | */ 414 | Component{ 415 | id: mailListSectionDelegate 416 | ListItem.Subheader{ 417 | backgroundColor: Theme.backgroundColor 418 | height: Units.dp(40) 419 | Label{ 420 | anchors.verticalCenter: parent.verticalCenter 421 | text: section 422 | font.pixelSize: Units.dp(14) 423 | } 424 | ThinDivider{ 425 | anchors { 426 | left: parent.left 427 | right: parent.right 428 | bottom: parent.bottom 429 | } 430 | visible: true 431 | } 432 | } 433 | } 434 | 435 | Component{ 436 | id: mailListDelegate 437 | 438 | ListItem.Standard{ 439 | id: mailListItem 440 | 441 | width: mailListColumn.width 442 | height: Units.dp(100) 443 | 444 | backgroundColor: selectedMailIndex == index ? "silver" : globalBackgroundColor 445 | 446 | onClicked: { 447 | model.mail_isread = true; // update isread 448 | selectedMailIndex = index; 449 | 450 | pageLoader.changeMail(index) 451 | 452 | } 453 | 454 | Rectangle{ 455 | id: isreadRectangle 456 | height: parent.height 457 | 458 | width: Units.dp(5) 459 | color: model.mail_isread ? mailListItem.backgroundColor : "green" 460 | } 461 | 462 | ColumnLayout{ 463 | anchors.left: isreadRectangle.right 464 | anchors.margins: Units.dp(5) 465 | spacing: Units.dp(5) 466 | 467 | Label{ 468 | id: mailSender 469 | text: model.mail_sender.split('@')[0] 470 | font.bold: true 471 | Layout.fillWidth: true 472 | font.pixelSize: Units.dp(20) 473 | } 474 | 475 | Label{ 476 | id: mailTitle 477 | anchors.leftMargin: Units.dp(5) 478 | Layout.fillWidth: true 479 | text: model.mail_subject 480 | 481 | font.family: contentFont 482 | 483 | wrapMode: Text.WordWrap 484 | } 485 | 486 | Label{ 487 | id: mailContent 488 | anchors.leftMargin: Units.dp(5) 489 | Layout.fillWidth: true 490 | 491 | text: model.mail_content.split('\n')[0] 492 | font.family: contentFont 493 | wrapMode: Text.WordWrap 494 | 495 | } 496 | 497 | } 498 | 499 | 500 | ThinDivider{ 501 | anchors { 502 | left: parent.left 503 | right: parent.right 504 | bottom: parent.bottom 505 | } 506 | visible: true 507 | } 508 | 509 | } 510 | } 511 | } 512 | 513 | 514 | Loader{ 515 | 516 | id: pageLoader 517 | 518 | anchors.left: mailListColumn.right 519 | 520 | height: parent.height 521 | 522 | visible: isLargeWindow 523 | 524 | width: parent.width - mailListColumn.x - mailListColumn.width // How to simplify? 525 | 526 | // visible: selectedMailIndex >= 0 527 | 528 | // source: Qt.resolvedUrl("NewMailEdit.qml") 529 | 530 | // source: Qt.resolvedUrl("MailView.qml") 531 | 532 | function test() { 533 | console.log("parent.width = " + parent.width) 534 | console.log("mailListColumn.x = " + mailListColumn.x) 535 | console.log("mailListColumn.width = " + mailListColumn.width) 536 | } 537 | 538 | function changeMail(index) { 539 | setSource(Qt.resolvedUrl("MailView.qml")) 540 | item.loadHtml(mailListModel.getHTMLContent(index)) 541 | } 542 | 543 | function newMail(){ 544 | console.log("in Function newMail") 545 | setSource(Qt.resolvedUrl("NewMailEdit.qml")) 546 | 547 | } 548 | 549 | } 550 | 551 | AccountLogin{ 552 | id: loginDialog 553 | 554 | visible: false 555 | 556 | signInButton.onClicked: { 557 | user = addressText 558 | passwd = passwordText 559 | sendHost = loginDialog.sendHost 560 | receiveHost = loginDialog.receiveHost 561 | requireSSL = loginDialog.requireSSL 562 | 563 | mailListModel.setProtocol( loginDialog.selectedProtocol ) 564 | mailListModel.login(user, passwd, sendHost, receiveHost, requireSSL) 565 | 566 | loginDialog.close() 567 | snackbar.open("Login Successfully") 568 | } 569 | 570 | onClosed: visible = false 571 | } 572 | 573 | } // BackgroundRectangle 574 | } 575 | 576 | Snackbar{ 577 | id: snackbar 578 | 579 | } 580 | 581 | } 582 | 583 | -------------------------------------------------------------------------------- /MicroMailClient.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {7ea379e5-639c-4adc-8f9b-81df050fc799} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | 0 45 | 8 46 | true 47 | 1 48 | true 49 | true 50 | true 51 | false 52 | 53 | 54 | 55 | ProjectExplorer.Project.PluginSettings 56 | 57 | 58 | 59 | ProjectExplorer.Project.Target.0 60 | 61 | Desktop Qt 5.6.0 MSVC2015 32bit 62 | Desktop Qt 5.6.0 MSVC2015 32bit 63 | qt.56.win32_msvc2015_kit 64 | 1 65 | 0 66 | 0 67 | 68 | C:/Users/37567/Documents/Visual Studio 2015/Projects/MicroMailClient-QT/build-MicroMailClient-Desktop_Qt_5_6_0_MSVC2015_32bit-Debug 69 | 70 | 71 | true 72 | qmake 73 | 74 | QtProjectManager.QMakeBuildStep 75 | true 76 | 77 | false 78 | false 79 | false 80 | 81 | 82 | true 83 | Make 84 | 85 | Qt4ProjectManager.MakeStep 86 | 87 | false 88 | 89 | 90 | 91 | 2 92 | Build 93 | 94 | ProjectExplorer.BuildSteps.Build 95 | 96 | 97 | 98 | true 99 | Make 100 | 101 | Qt4ProjectManager.MakeStep 102 | 103 | true 104 | clean 105 | 106 | 107 | 1 108 | Clean 109 | 110 | ProjectExplorer.BuildSteps.Clean 111 | 112 | 2 113 | false 114 | 115 | Debug 116 | 117 | Qt4ProjectManager.Qt4BuildConfiguration 118 | 2 119 | true 120 | 121 | 122 | C:/Users/37567/Documents/Visual Studio 2015/Projects/MicroMailClient-QT/build-MicroMailClient-Desktop_Qt_5_6_0_MSVC2015_32bit-Debug 123 | 124 | 125 | true 126 | qmake 127 | 128 | QtProjectManager.QMakeBuildStep 129 | false 130 | 131 | false 132 | false 133 | false 134 | 135 | 136 | true 137 | Make 138 | 139 | Qt4ProjectManager.MakeStep 140 | 141 | false 142 | 143 | 144 | 145 | 2 146 | Build 147 | 148 | ProjectExplorer.BuildSteps.Build 149 | 150 | 151 | 152 | true 153 | Make 154 | 155 | Qt4ProjectManager.MakeStep 156 | 157 | true 158 | clean 159 | 160 | 161 | 1 162 | Clean 163 | 164 | ProjectExplorer.BuildSteps.Clean 165 | 166 | 2 167 | false 168 | 169 | Release 170 | 171 | Qt4ProjectManager.Qt4BuildConfiguration 172 | 0 173 | true 174 | 175 | 176 | C:/Users/37567/Documents/Visual Studio 2015/Projects/MicroMailClient-QT/build-MicroMailClient-Desktop_Qt_5_6_0_MSVC2015_32bit-Profile 177 | 178 | 179 | true 180 | qmake 181 | 182 | QtProjectManager.QMakeBuildStep 183 | true 184 | 185 | false 186 | true 187 | false 188 | 189 | 190 | true 191 | Make 192 | 193 | Qt4ProjectManager.MakeStep 194 | 195 | false 196 | 197 | 198 | 199 | 2 200 | Build 201 | 202 | ProjectExplorer.BuildSteps.Build 203 | 204 | 205 | 206 | true 207 | Make 208 | 209 | Qt4ProjectManager.MakeStep 210 | 211 | true 212 | clean 213 | 214 | 215 | 1 216 | Clean 217 | 218 | ProjectExplorer.BuildSteps.Clean 219 | 220 | 2 221 | false 222 | 223 | Profile 224 | 225 | Qt4ProjectManager.Qt4BuildConfiguration 226 | 0 227 | true 228 | 229 | 3 230 | 231 | 232 | 0 233 | Deploy 234 | 235 | ProjectExplorer.BuildSteps.Deploy 236 | 237 | 1 238 | Deploy locally 239 | 240 | ProjectExplorer.DefaultDeployConfiguration 241 | 242 | 1 243 | 244 | 245 | false 246 | 1000 247 | 248 | true 249 | 250 | false 251 | false 252 | false 253 | false 254 | true 255 | 0.01 256 | 10 257 | true 258 | 1 259 | 25 260 | 261 | 1 262 | true 263 | false 264 | true 265 | valgrind 266 | 267 | 0 268 | 1 269 | 2 270 | 3 271 | 4 272 | 5 273 | 6 274 | 7 275 | 8 276 | 9 277 | 10 278 | 11 279 | 12 280 | 13 281 | 14 282 | 283 | 2 284 | 285 | MicroMailClient 286 | 287 | Qt4ProjectManager.Qt4RunConfiguration:C:/Users/37567/Documents/Visual Studio 2015/Projects/MicroMailClient-QT/MicroMailClient/MicroMailClient.pro 288 | true 289 | 290 | MicroMailClient.pro 291 | false 292 | false 293 | 294 | 3768 295 | false 296 | true 297 | false 298 | false 299 | true 300 | 301 | 1 302 | 303 | 304 | 305 | ProjectExplorer.Project.TargetCount 306 | 1 307 | 308 | 309 | ProjectExplorer.Project.Updater.FileVersion 310 | 18 311 | 312 | 313 | Version 314 | 18 315 | 316 | 317 | -------------------------------------------------------------------------------- /NewMailEdit.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.6 2 | import QtQuick.Controls 1.4 3 | import QtQuick.Window 2.2 4 | import QtQuick.Layouts 1.1 5 | import QtQuick.Dialogs 1.2 6 | import Material 0.2 7 | import Material.ListItems 0.1 as ListItem 8 | import QtWebEngine 1.2 9 | 10 | Item { 11 | 12 | id:newMailRectangle 13 | 14 | //@Zach's param 15 | property bool isTextBold: false 16 | property bool textReadyToBold: false 17 | property bool textReadyNotBold: false 18 | property bool isTextItalic: false 19 | property bool textReadyToItalic: false 20 | property bool textReadyNotItalic: false 21 | property bool isTextUnderline: false 22 | property bool textReadyToUnderline: false 23 | property bool textReadyNotUnderline: false 24 | property bool isTextStrikeout: false 25 | property bool textReadyToStrikeout: false 26 | property bool textReadyNotStrikeout: false 27 | property bool isTextSubscript: false 28 | property bool textReadyToSub: false 29 | property bool textReadyNotSub: false 30 | property bool isTextSuperscript: false 31 | property bool textReadyToSup: false 32 | property bool textReadyNotSup: false 33 | 34 | property string textColor: "black" 35 | property string selectedPlainText: "" 36 | property string selectedFormattedText: "" 37 | property var textFontFamily: [ 38 | "Arial", "Calibri", "Courier New", "Microsoft YaHei", "宋体"] 39 | property var textFontSize: [ 40 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 41 | 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 42 | 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] 43 | property var attachmentList : [] 44 | 45 | 46 | //@Zach's param end 47 | 48 | anchors.fill: parent 49 | 50 | ColumnLayout{ 51 | id:newMailRectangleColumn 52 | anchors.fill: parent 53 | anchors.margins: Units.dp(10) 54 | anchors.topMargin: 0 55 | spacing: Units.dp(8) 56 | 57 | RowLayout{ 58 | id : mailViewToolBar 59 | 60 | height: Units.dp(60) 61 | 62 | spacing: 0 63 | 64 | anchors.top : parent.top 65 | 66 | anchors.right: parent.right 67 | 68 | Layout.fillWidth : true 69 | 70 | MyButton{ 71 | id : sendMailButton 72 | label : "Send" 73 | source: "/icons/send" 74 | Layout.preferredWidth: Units.dp(label.length*8 + 60) 75 | onClicked: { 76 | console.log(typeof(attachmentList), attachmentList) 77 | mailListModel.sendMail(recipientTextField.text, subjectTextField.text, newMailTextEdit.getFormattedText(0, newMailTextEdit.text.length), attachmentList) 78 | snackbar.open("Mail Send Successfully") 79 | } 80 | 81 | } 82 | 83 | MyButton{ 84 | id : clearButton 85 | label: "Reply" 86 | source: "/icons/clear" 87 | Layout.preferredWidth: Units.dp(label.length*8 + 60) 88 | 89 | } 90 | 91 | MyButton{ 92 | id : replyAllButton 93 | label: "Reply All" 94 | source: "/icons/reply_all" 95 | Layout.preferredWidth: Units.dp(label.length*8 + 60) 96 | } 97 | 98 | } 99 | 100 | 101 | Rectangle{ 102 | id: editTextButtonRectangle 103 | anchors.left: parent.left 104 | width: 0.95*parent.width 105 | height: Units.dp(45) 106 | 107 | color:"#E0E0E0" 108 | 109 | RowLayout{ 110 | anchors.fill: parent 111 | 112 | Button{ 113 | id: textBoldButton 114 | Layout.preferredWidth: Units.dp(45) 115 | Label{ 116 | 117 | anchors.horizontalCenter: parent.horizontalCenter 118 | anchors.verticalCenter: parent.verticalCenter 119 | text:"B" 120 | font.bold: true 121 | font.pixelSize: 30 122 | } 123 | 124 | onClicked: { 125 | var start = newMailTextEdit.selectionStart 126 | var end = newMailTextEdit.selectionEnd 127 | selectedFormattedText = newMailTextEdit.getFormattedText(start, end) 128 | selectedPlainText=newMailTextEdit.selectedText 129 | var hasSelected=(start==end)? false: true 130 | 131 | 132 | if(hasSelected){ 133 | if(selectedFormattedText.indexOf("font-weight:600;")!=-1) 134 | { 135 | newMailTextEdit.remove(start, end) 136 | newMailTextEdit.insert(start, selectedPlainText) 137 | isTextBold=false 138 | newMailTextEdit.select(start, end) 139 | } 140 | else{ 141 | newMailTextEdit.remove(start, end) 142 | newMailTextEdit.insert(start, "" + selectedPlainText +"") 143 | isTextBold=true 144 | newMailTextEdit.select(start, end) 145 | } 146 | } 147 | else{ 148 | if(isTextBold){ 149 | isTextBold=false 150 | textReadyToBold=false 151 | textReadyNotBold=true 152 | } 153 | else{ 154 | isTextBold=true 155 | textReadyToBold=true 156 | textReadyNotBold=false 157 | } 158 | } 159 | } 160 | 161 | backgroundColor: isTextBold?(Qt.darker(editTextButtonRectangle.color, 1.2)):editTextButtonRectangle.color 162 | } 163 | 164 | Button{ 165 | id: textItalicButton 166 | Layout.preferredWidth: Units.dp(45) 167 | Label{ 168 | anchors.horizontalCenter: parent.horizontalCenter 169 | anchors.verticalCenter: parent.verticalCenter 170 | text:"I" 171 | font.italic: true 172 | font.pixelSize: 30 173 | } 174 | onClicked: { 175 | var start = newMailTextEdit.selectionStart 176 | var end = newMailTextEdit.selectionEnd 177 | selectedFormattedText = newMailTextEdit.getFormattedText(start, end) 178 | selectedPlainText=newMailTextEdit.selectedText 179 | var hasSelected=(start==end)? false: true 180 | 181 | 182 | if(hasSelected){ 183 | if(selectedFormattedText.indexOf("font-style:italic;")!=-1) 184 | { 185 | newMailTextEdit.remove(start, end) 186 | newMailTextEdit.insert(start, selectedPlainText) 187 | isTextItalic=false 188 | newMailTextEdit.select(start, end) 189 | } 190 | else{ 191 | newMailTextEdit.remove(start, end) 192 | newMailTextEdit.insert(start, "" + selectedPlainText +"") 193 | isTextItalic=true 194 | newMailTextEdit.select(start, end) 195 | } 196 | } 197 | else{ 198 | if(isTextItalic){ 199 | isTextItalic=false 200 | textReadyToItalic=false 201 | textReadyNotItalic=true 202 | } 203 | else{ 204 | isTextItalic=true 205 | textReadyToItalic=true 206 | textReadyNotItalic=false 207 | } 208 | } 209 | } 210 | backgroundColor: isTextItalic?(Qt.darker(editTextButtonRectangle.color, 1.2)):editTextButtonRectangle.color 211 | } 212 | 213 | Button{ 214 | id: textUnderlineButton 215 | Layout.preferredWidth: Units.dp(45) 216 | Label{ 217 | anchors.horizontalCenter: parent.horizontalCenter 218 | anchors.verticalCenter: parent.verticalCenter 219 | text:"U" 220 | font.underline: true 221 | font.pixelSize: 30 222 | } 223 | 224 | onClicked: { 225 | var start = newMailTextEdit.selectionStart 226 | var end = newMailTextEdit.selectionEnd 227 | selectedFormattedText = newMailTextEdit.getFormattedText(start, end) 228 | selectedPlainText=newMailTextEdit.selectedText 229 | var hasSelected=(start==end)? false: true 230 | 231 | if(hasSelected){ 232 | if(selectedFormattedText.indexOf("text-decoration: underline")!=-1) 233 | { 234 | newMailTextEdit.remove(start, end) 235 | newMailTextEdit.insert(start, "" + selectedPlainText) 236 | isTextUnderline=false 237 | newMailTextEdit.select(start, end) 238 | } 239 | else{ 240 | newMailTextEdit.remove(start, end) 241 | newMailTextEdit.insert(start, "" + selectedPlainText +"") 242 | isTextUnderline=true 243 | newMailTextEdit.select(start, end) 244 | } 245 | } 246 | else{ 247 | if(isTextUnderline){ 248 | isTextUnderline=false 249 | textReadyToUnderline=false 250 | textReadyNotUnderline=true 251 | } 252 | else{ 253 | isTextUnderline=true 254 | textReadyToUnderline=true 255 | textReadyNotUnderline=false 256 | } 257 | } 258 | } 259 | backgroundColor: isTextUnderline?(Qt.darker(editTextButtonRectangle.color, 1.2)):editTextButtonRectangle.color 260 | } 261 | 262 | Button{ 263 | id: textStrikeoutButton 264 | Layout.preferredWidth: Units.dp(45) 265 | Label{ 266 | anchors.horizontalCenter: parent.horizontalCenter 267 | anchors.verticalCenter: parent.verticalCenter 268 | text:"ab" 269 | font.strikeout: true 270 | font.pixelSize: 30 271 | } 272 | backgroundColor: isTextStrikeout?(Qt.darker(editTextButtonRectangle.color, 1.2)):editTextButtonRectangle.color 273 | 274 | onClicked: { 275 | var start = newMailTextEdit.selectionStart 276 | var end = newMailTextEdit.selectionEnd 277 | selectedFormattedText = newMailTextEdit.getFormattedText(start, end) 278 | selectedPlainText=newMailTextEdit.selectedText 279 | var hasSelected=(start==end)? false: true 280 | 281 | 282 | if(hasSelected){ 283 | if(selectedFormattedText.indexOf("text-decoration: line-through")!=-1) 284 | { 285 | newMailTextEdit.remove(start, end) 286 | newMailTextEdit.insert(start, "" + selectedPlainText) 287 | isTextStrikeout=false 288 | newMailTextEdit.select(start, end) 289 | } 290 | else{ 291 | newMailTextEdit.remove(start, end) 292 | newMailTextEdit.insert(start, "" + selectedPlainText +"") 293 | isTextStrikeout=true 294 | newMailTextEdit.select(start, end) 295 | } 296 | } 297 | else{ 298 | if(isTextStrikeout){ 299 | isTextStrikeout=false 300 | textReadyToStrikeout=false 301 | textReadyNotStrikeout=true 302 | } 303 | else{ 304 | isTextStrikeout=true 305 | textReadyToStrikeout=true 306 | textReadyNotStrikeout=false 307 | } 308 | } 309 | } 310 | } 311 | 312 | MenuField{ 313 | id:fontMenuField 314 | 315 | model:textFontFamily 316 | Layout.alignment: Qt.AlignLeft 317 | Layout.preferredWidth: Units.dp(240) 318 | selectedIndex: 3 319 | 320 | Layout.fillWidth: true 321 | 322 | // onSelectedIndexChanged: { 323 | // var start = newMailTextEdit.selectionStart 324 | // var end = newMailTextEdit.selectionEnd 325 | // selectedFormattedText = newMailTextEdit.getFormattedText(start, end) 326 | // selectedPlainText=newMailTextEdit.selectedText 327 | // var hasSelected=(start==end)? false: true 328 | 329 | // if(hasSelected){ 330 | // newMailTextEdit.remove(start, end) 331 | // newMailTextEdit.insert(start, "" + selectedPlainText +"") 332 | // newMailTextEdit.select(start, end) 333 | // } 334 | // console.log(newMailTextEdit.getFormattedText(start, end)) 335 | // } 336 | } 337 | 338 | MenuField{ 339 | id:fontSizeMenuField 340 | Layout.preferredWidth: Units.dp(60) 341 | model:textFontSize 342 | selectedIndex: 15 343 | } 344 | 345 | Button{ 346 | id: textSubscriptButton 347 | Layout.preferredWidth: Units.dp(45) 348 | Label{ 349 | anchors.horizontalCenter: parent.horizontalCenter 350 | anchors.verticalCenter: parent.verticalCenter 351 | text:"x2" 352 | textFormat: Text.RichText 353 | font.pixelSize: 25 354 | } 355 | backgroundColor: isTextSubscript?(Qt.darker(editTextButtonRectangle.color, 1.2)):editTextButtonRectangle.color 356 | onClicked: { 357 | var start = newMailTextEdit.selectionStart 358 | var end = newMailTextEdit.selectionEnd 359 | selectedFormattedText = newMailTextEdit.getFormattedText(start, end) 360 | selectedPlainText=newMailTextEdit.selectedText 361 | var hasSelected=(start==end)? false: true 362 | 363 | 364 | if(hasSelected){ 365 | if(selectedFormattedText.indexOf("vertical-align:sub")!=-1) 366 | { 367 | newMailTextEdit.remove(start, end) 368 | newMailTextEdit.insert(start, selectedPlainText) 369 | isTextSubscript=false 370 | newMailTextEdit.select(start, end) 371 | } 372 | else{ 373 | newMailTextEdit.remove(start, end) 374 | newMailTextEdit.insert(start, "" + selectedPlainText +"") 375 | isTextSubscript=true 376 | newMailTextEdit.select(start, end) 377 | } 378 | } 379 | else{ 380 | if(isTextSubscript){ 381 | isTextSubscript=false 382 | textReadyToSub=false 383 | textReadyNotSub=true 384 | } 385 | else{ 386 | isTextSubscript=true 387 | textReadyToSub=true 388 | textReadyNotSub=false 389 | } 390 | } 391 | } 392 | } 393 | 394 | Button{ 395 | id: textSuperscriptButton 396 | Layout.preferredWidth: Units.dp(45) 397 | // anchors.left: textSubscriptButton.right 398 | Label{ 399 | anchors.horizontalCenter: parent.horizontalCenter 400 | anchors.verticalCenter: parent.verticalCenter 401 | text:"x2" 402 | textFormat: Text.RichText 403 | font.pixelSize: 25 404 | } 405 | backgroundColor: isTextSuperscript?(Qt.darker(editTextButtonRectangle.color, 1.2)):editTextButtonRectangle.color 406 | onClicked: { 407 | var start = newMailTextEdit.selectionStart 408 | var end = newMailTextEdit.selectionEnd 409 | selectedFormattedText = newMailTextEdit.getFormattedText(start, end) 410 | selectedPlainText=newMailTextEdit.selectedText 411 | var hasSelected=(start==end)? false: true 412 | 413 | 414 | if(hasSelected){ 415 | if(selectedFormattedText.indexOf("vertical-align:super")!=-1) 416 | { 417 | newMailTextEdit.remove(start, end) 418 | newMailTextEdit.insert(start, selectedPlainText) 419 | isTextSuperscript=false 420 | newMailTextEdit.select(start, end) 421 | } 422 | else{ 423 | newMailTextEdit.remove(start, end) 424 | newMailTextEdit.insert(start, "" + selectedPlainText +"") 425 | isTextSuperscript=true 426 | newMailTextEdit.select(start, end) 427 | } 428 | } 429 | else{ 430 | if(isTextSuperscript){ 431 | isTextSuperscript=false 432 | textReadyToSup=false 433 | textReadyNotSup=true 434 | } 435 | else{ 436 | isTextSuperscript=true 437 | textReadyToSup=true 438 | textReadyNotSup=false 439 | } 440 | } 441 | } 442 | } 443 | 444 | Button{ 445 | id: textColorPickButton 446 | Layout.preferredWidth: Units.dp(45) 447 | 448 | Label{ 449 | anchors.horizontalCenter: parent.horizontalCenter 450 | anchors.verticalCenter: parent.verticalCenter 451 | text:"A" 452 | textFormat: Text.RichText 453 | font.pixelSize: 25 454 | } 455 | onClicked: colorPicker.open() 456 | backgroundColor: editTextButtonRectangle.color 457 | } 458 | } 459 | } //end of editTextButtonRectangle 460 | 461 | ListItem.Standard{ 462 | id:newMailSender 463 | content:RowLayout{ 464 | Label{ 465 | id: newMailFromLabel 466 | Layout.preferredWidth: Units.dp(35) 467 | text:"From: " 468 | } 469 | 470 | MenuField{ 471 | model:[ user ] 472 | Layout.preferredWidth: 0.9*newMailSender.width-newMailFromLabel.width 473 | } 474 | } 475 | } 476 | 477 | ListItem.Standard{ 478 | id: newMailReceiver 479 | content:RowLayout{ 480 | width: parent.width* 0.95 481 | 482 | Label{ 483 | id: toReceiverLabel 484 | text:"To: " 485 | Layout.alignment:Qt.AlignLeft 486 | Layout.preferredWidth: Units.dp(20) 487 | } 488 | 489 | TextField{ 490 | id: recipientTextField 491 | Layout.preferredWidth: parent.width-toReceiverLabel.width-1.1*ccBCCButton.width 492 | } 493 | 494 | MyButton{ 495 | id:ccBCCButton 496 | text:"CC & BCC" 497 | anchors.right: parent.right 498 | onClicked: { 499 | ccMailReceiver.visible= !ccMailReceiver.visible 500 | bccMailReceiver.visible=!bccMailReceiver.visible 501 | } 502 | } 503 | } 504 | }//end of newMailReceiver 505 | 506 | ListItem.Standard{ 507 | id:ccMailReceiver 508 | visible:false 509 | content:RowLayout{ 510 | width: parent.width* 0.95 511 | 512 | Label{ 513 | id: ccReceiverLabel 514 | text:"CC: " 515 | Layout.alignment:Qt.AlignLeft 516 | Layout.preferredWidth: Units.dp(20) 517 | } 518 | 519 | TextField{ 520 | id: ccTextField 521 | Layout.preferredWidth: parent.width-ccReceiverLabel.width 522 | } 523 | } 524 | } 525 | 526 | ListItem.Standard{ 527 | id:bccMailReceiver 528 | visible:false 529 | content:RowLayout{ 530 | width: parent.width* 0.95 531 | 532 | Label{ 533 | id: bccReceiverLabel 534 | text:"BCC: " 535 | Layout.alignment:Qt.AlignLeft 536 | Layout.preferredWidth: Units.dp(28) 537 | } 538 | 539 | TextField{ 540 | id: bccTextField 541 | Layout.preferredWidth: parent.width-bccReceiverLabel.width 542 | } 543 | } 544 | } 545 | 546 | ListItem.Standard{ 547 | id:newMailSubject 548 | content: RowLayout{ 549 | width:parent.width*0.95 550 | TextField{ 551 | id: subjectTextField 552 | anchors.left: parent.lest 553 | Layout.preferredWidth: parent.width-attachmentButton.width*1.1 554 | placeholderText: "Subject" 555 | } 556 | 557 | MyButton{ 558 | id:attachmentButton 559 | text:"attachment" 560 | anchors.right: parent.right 561 | onClicked: { 562 | attaPickerDialog.open() 563 | } 564 | } 565 | } 566 | } 567 | 568 | RowLayout{ 569 | id: attachmentRowLayout 570 | Layout.fillWidth: true 571 | height: Units.dp(50) 572 | visible: attachmentList.length > 0 573 | 574 | Repeater{ 575 | id: attachmentRepeater 576 | model: attachmentList 577 | delegate:Component{ 578 | MyButton{ 579 | source: "/icons/file" 580 | height: 0.95*parent.height 581 | label: modelData.substr(modelData.lastIndexOf('/')+1) 582 | } 583 | } 584 | } 585 | } 586 | 587 | TextEdit { 588 | id: newMailTextEdit 589 | 590 | anchors.margins: Units.dp(10) 591 | cursorVisible: true //debug 592 | Layout.fillHeight: true 593 | Layout.fillWidth: true 594 | 595 | font.pixelSize: fontSizeMenuField.selectedIndex + 1 596 | font.family: fontMenuField.selectedText 597 | 598 | color: textColor // should be the picked color 599 | 600 | Keys.onReleased: { 601 | if(isTextBold && textReadyToBold) 602 | { 603 | var currentCursor=newMailTextEdit.cursorPosition 604 | var ch=newMailTextEdit.getText(currentCursor-1,currentCursor) 605 | newMailTextEdit.remove(currentCursor-1, currentCursor) 606 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch+"") 607 | textReadyToBold=false 608 | } 609 | else if(!isTextBold && textReadyNotBold) 610 | { 611 | var currentCursor2=newMailTextEdit.cursorPosition 612 | var ch2=newMailTextEdit.getText(currentCursor2-1,currentCursor2) 613 | newMailTextEdit.remove(currentCursor2-1, currentCursor2) 614 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch2+"") 615 | textReadyNotBold=false 616 | } 617 | 618 | if(isTextItalic && textReadyToItalic) 619 | { 620 | var currentCursor3=newMailTextEdit.cursorPosition 621 | var ch3=newMailTextEdit.getText(currentCursor3-1,currentCursor3) 622 | newMailTextEdit.remove(currentCursor3-1, currentCursor3) 623 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch3+"") 624 | textReadyToItalic=false 625 | } 626 | else if(!isTextItalic && textReadyNotItalic) 627 | { 628 | var currentCursor4=newMailTextEdit.cursorPosition 629 | var ch4=newMailTextEdit.getText(currentCursor4-1,currentCursor4) 630 | newMailTextEdit.remove(currentCursor4-1, currentCursor4) 631 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch4+"") 632 | textReadyNotItalic=false 633 | } 634 | 635 | if(isTextUnderline && textReadyToUnderline) 636 | { 637 | var currentCursor5=newMailTextEdit.cursorPosition 638 | var ch5=newMailTextEdit.getText(currentCursor5-1,currentCursor5) 639 | newMailTextEdit.remove(currentCursor5-1, currentCursor5) 640 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch5+"") 641 | textReadyToUnderline=false 642 | } 643 | else if(!isTextUnderline && textReadyNotUnderline) 644 | { 645 | var currentCursor6=newMailTextEdit.cursorPosition 646 | var ch6=newMailTextEdit.getText(currentCursor6-1,currentCursor6) 647 | newMailTextEdit.remove(currentCursor6-1, currentCursor6) 648 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch6+"") 649 | textReadyNotUnderline=false 650 | } 651 | 652 | if(isTextStrikeout && textReadyToStrikeout) 653 | { 654 | var currentCursor7=newMailTextEdit.cursorPosition 655 | var ch7=newMailTextEdit.getText(currentCursor7-1,currentCursor7) 656 | newMailTextEdit.remove(currentCursor7-1, currentCursor7) 657 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch7+"") 658 | textReadyToStrikeout=false 659 | } 660 | else if(!isTextStrikeout && textReadyNotStrikeout) 661 | { 662 | var currentCursor8=newMailTextEdit.cursorPosition 663 | var ch8=newMailTextEdit.getText(currentCursor8-1,currentCursor8) 664 | newMailTextEdit.remove(currentCursor8-1, currentCursor8) 665 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch8+"") 666 | textReadyNotStrikeout=false 667 | } 668 | 669 | if(isTextSubscript && textReadyToSub) 670 | { 671 | var currentCursor9=newMailTextEdit.cursorPosition 672 | var ch9=newMailTextEdit.getText(currentCursor9-1,currentCursor9) 673 | newMailTextEdit.remove(currentCursor9-1, currentCursor9) 674 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+ch9+"") 675 | textReadyToSub=false 676 | } 677 | else if(!isTextSubscript && textReadyNotSub) 678 | { 679 | var currentCursorA=newMailTextEdit.cursorPosition 680 | var chA=newMailTextEdit.getText(currentCursorA-1,currentCursorA) 681 | newMailTextEdit.remove(currentCursorA-1, currentCursorA) 682 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+chA+"") 683 | textReadyNotSub=false 684 | } 685 | 686 | if(isTextSuperscript && textReadyToSup) 687 | { 688 | var currentCursorB=newMailTextEdit.cursorPosition 689 | var chB=newMailTextEdit.getText(currentCursorB-1,currentCursorB) 690 | newMailTextEdit.remove(currentCursorB-1, currentCursorB) 691 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+chB+"") 692 | textReadyToSup=false 693 | } 694 | else if(!isTextSuperscript && textReadyNotSup) 695 | { 696 | var currentCursorC=newMailTextEdit.cursorPosition 697 | var chC=newMailTextEdit.getText(currentCursorC-1,currentCursorC) 698 | newMailTextEdit.remove(currentCursorC-1, currentCursorC) 699 | newMailTextEdit.insert(newMailTextEdit.cursorPosition, ""+chC+"") 700 | textReadyNotSup=false 701 | } 702 | } 703 | 704 | // property string tmpFormattedString 705 | 706 | // onCursorPositionChanged: { 707 | // tmpFormattedString=getFormattedText(cursorPosition-1, cursorPosition) 708 | 709 | // if(tmpFormattedString.indexOf("font-weight:600")!=-1) 710 | // isTextBold=true 711 | // else 712 | // isTextBold=false 713 | // if(tmpFormattedString.indexOf("font-style:italic")!=-1) 714 | // isTextItalic=true 715 | // else 716 | // isTextItalic=false 717 | // if(tmpFormattedString.indexOf("text-decoration: underline")!=-1) 718 | // isTextUnderline=true 719 | // else 720 | // isTextUnderline=false 721 | // if(tmpFormattedString.indexOf("text-decoration: line-through")!=-1) 722 | // isTextStrikeout=true 723 | // else 724 | // isTextStrikeout=false 725 | // if(tmpFormattedString.indexOf("vertical-align:sub")!=-1) 726 | // isTextSubscript=true 727 | // else 728 | // isTextSubscript=false 729 | // if(tmpFormattedString.indexOf("vertical-align:super")!=-1) 730 | // isTextSuperscript=true 731 | // else 732 | // isTextSuperscript=false 733 | // } 734 | 735 | wrapMode: TextEdit.Wrap 736 | 737 | textFormat: TextEdit.RichText 738 | 739 | } 740 | 741 | } //end of columnlayout 742 | 743 | Dialog { 744 | id: colorPicker 745 | hasActions: true 746 | title: "Pick font color" 747 | positiveButtonText: "Done" 748 | 749 | Grid { 750 | columns: 7 751 | spacing: Units.dp(8) 752 | 753 | Repeater { 754 | model: [ 755 | "red", "pink", "purple", "deepPurple", "indigo", 756 | "blue", "lightBlue", "cyan", "teal", "green", 757 | "lightGreen", "lime", "yellow", "amber", "orange", 758 | "deepOrange", "grey", "blueGrey", "brown", "black", 759 | "white" 760 | ] 761 | 762 | Rectangle { 763 | width: Units.dp(30) 764 | height: Units.dp(30) 765 | radius: Units.dp(2) 766 | color: Palette.colors[modelData]["500"] 767 | border.width: modelData === "white" ? Units.dp(2) : 0 768 | border.color: Theme.alpha("#000", 0.26) 769 | 770 | Ink { 771 | anchors.fill: parent 772 | 773 | onPressed: { 774 | newMailTextEdit.color = parent.color 775 | } 776 | } 777 | } 778 | } 779 | } 780 | 781 | onOpened: { 782 | console.log("color picker dialog opened") 783 | } 784 | 785 | onRejected: { 786 | // TODO set default colors again but we currently don't know what that is 787 | } 788 | }//end of colorPickerDialog 789 | 790 | FileDialog{ 791 | 792 | id:attaPickerDialog 793 | 794 | title: "Please choose attachments" 795 | 796 | folder: shortcuts.desktop 797 | 798 | selectMultiple: true 799 | 800 | onAccepted:{ 801 | attachmentList=String(attaPickerDialog.fileUrls).split(',') 802 | attachmentRowLayout.visible=true 803 | } 804 | onRejected:{ 805 | attachmentList=[] 806 | } 807 | } 808 | } 809 | --------------------------------------------------------------------------------