├── 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 |
--------------------------------------------------------------------------------