huge work on gmail previewer, some refactoring, some fixes

This commit is contained in:
Martin Rotter 2022-03-31 15:00:50 +02:00
parent 55571a9d44
commit 8dac36b37c
23 changed files with 191 additions and 60 deletions

View File

@ -26,7 +26,7 @@
<url type="donation">https://github.com/sponsors/martinrotter</url> <url type="donation">https://github.com/sponsors/martinrotter</url>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
<releases> <releases>
<release version="4.2.1" date="2022-03-30"/> <release version="4.2.1" date="2022-03-31"/>
</releases> </releases>
<content_rating type="oars-1.0"> <content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">none</content_attribute> <content_attribute id="violence-cartoon">none</content_attribute>

View File

@ -50,6 +50,7 @@
<file>./graphics/Breeze/actions/22/list-add.svg</file> <file>./graphics/Breeze/actions/22/list-add.svg</file>
<file>./graphics/Breeze/actions/22/list-remove.svg</file> <file>./graphics/Breeze/actions/22/list-remove.svg</file>
<file>./graphics/Breeze/actions/32/mail-attachment.svg</file> <file>./graphics/Breeze/actions/32/mail-attachment.svg</file>
<file>./graphics/Breeze/actions/32/mail-forward.svg</file>
<file>./graphics/Breeze/actions/symbolic/mail-inbox-symbolic.svg</file> <file>./graphics/Breeze/actions/symbolic/mail-inbox-symbolic.svg</file>
<file>./graphics/Breeze/actions/32/mail-mark-important.svg</file> <file>./graphics/Breeze/actions/32/mail-mark-important.svg</file>
<file>./graphics/Breeze/actions/32/mail-mark-junk.svg</file> <file>./graphics/Breeze/actions/32/mail-mark-junk.svg</file>
@ -125,6 +126,7 @@
<file>./graphics/Breeze Dark/actions/22/list-add.svg</file> <file>./graphics/Breeze Dark/actions/22/list-add.svg</file>
<file>./graphics/Breeze Dark/actions/22/list-remove.svg</file> <file>./graphics/Breeze Dark/actions/22/list-remove.svg</file>
<file>./graphics/Breeze Dark/actions/32/mail-attachment.svg</file> <file>./graphics/Breeze Dark/actions/32/mail-attachment.svg</file>
<file>./graphics/Breeze Dark/actions/32/mail-forward.svg</file>
<file>./graphics/Breeze Dark/actions/symbolic/mail-inbox-symbolic.svg</file> <file>./graphics/Breeze Dark/actions/symbolic/mail-inbox-symbolic.svg</file>
<file>./graphics/Breeze Dark/actions/32/mail-mark-important.svg</file> <file>./graphics/Breeze Dark/actions/32/mail-mark-important.svg</file>
<file>./graphics/Breeze Dark/actions/32/mail-mark-junk.svg</file> <file>./graphics/Breeze Dark/actions/32/mail-mark-junk.svg</file>
@ -198,6 +200,7 @@
<file>./graphics/Faenza/actions/64/list-add.png</file> <file>./graphics/Faenza/actions/64/list-add.png</file>
<file>./graphics/Faenza/actions/64/list-remove.png</file> <file>./graphics/Faenza/actions/64/list-remove.png</file>
<file>./graphics/Faenza/actions/64/mail-attachment.png</file> <file>./graphics/Faenza/actions/64/mail-attachment.png</file>
<file>./graphics/Faenza/actions/64/mail-forward.png</file>
<file>./graphics/Faenza/actions/64/mail-inbox.png</file> <file>./graphics/Faenza/actions/64/mail-inbox.png</file>
<file>./graphics/Faenza/actions/64/mail-mark-important.png</file> <file>./graphics/Faenza/actions/64/mail-mark-important.png</file>
<file>./graphics/Faenza/actions/64/mail-mark-junk.png</file> <file>./graphics/Faenza/actions/64/mail-mark-junk.png</file>
@ -277,6 +280,7 @@
<file>./graphics/Numix/22/actions/list-add.svg</file> <file>./graphics/Numix/22/actions/list-add.svg</file>
<file>./graphics/Numix/22/actions/list-remove.svg</file> <file>./graphics/Numix/22/actions/list-remove.svg</file>
<file>./graphics/Numix/22/actions/mail-attachment.svg</file> <file>./graphics/Numix/22/actions/mail-attachment.svg</file>
<file>./graphics/Numix/22/actions/mail-forward.svg</file>
<file>./graphics/Numix/22/places/mail-inbox.svg</file> <file>./graphics/Numix/22/places/mail-inbox.svg</file>
<file>./graphics/Numix/22/actions/mail-mark-important.svg</file> <file>./graphics/Numix/22/actions/mail-mark-important.svg</file>
<file>./graphics/Numix/22/actions/mail-mark-junk.svg</file> <file>./graphics/Numix/22/actions/mail-mark-junk.svg</file>

View File

@ -17,10 +17,8 @@
#include <QDebug> #include <QDebug>
#include <QJSEngine> #include <QJSEngine>
#include <QMutexLocker> #include <QMutexLocker>
#include <QRegularExpression>
#include <QString> #include <QString>
#include <QThread> #include <QThread>
#include <QUrl>
FeedDownloader::FeedDownloader() FeedDownloader::FeedDownloader()
: QObject(), m_isCacheSynchronizationRunning(false), m_stopCacheSynchronization(false), m_mutex(new QMutex()), m_feedsUpdated(0), m_feedsOriginalCount(0) { : QObject(), m_isCacheSynchronizationRunning(false), m_stopCacheSynchronization(false), m_mutex(new QMutex()), m_feedsUpdated(0), m_feedsOriginalCount(0) {

View File

@ -10,30 +10,26 @@
#include "miscellaneous/feedreader.h" #include "miscellaneous/feedreader.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/textfactory.h" #include "miscellaneous/textfactory.h"
#include "services/abstract/category.h"
#include "services/abstract/feed.h" #include "services/abstract/feed.h"
#include "services/abstract/recyclebin.h" #include "services/abstract/recyclebin.h"
#include "services/abstract/serviceentrypoint.h" #include "services/abstract/serviceentrypoint.h"
#include "services/abstract/serviceroot.h" #include "services/abstract/serviceroot.h"
#include "services/standard/standardserviceentrypoint.h"
#include "services/standard/standardserviceroot.h" #include "services/standard/standardserviceroot.h"
#include <QMimeData> #include <QMimeData>
#include <QPair> #include <QPair>
#include <QSqlError> #include <QSqlError>
#include <QSqlRecord>
#include <QStack> #include <QStack>
#include <QTimer> #include <QTimer>
#include <algorithm>
using RootItemPtr = RootItem*; using RootItemPtr = RootItem*;
FeedsModel::FeedsModel(QObject* parent) : QAbstractItemModel(parent) { FeedsModel::FeedsModel(QObject* parent) : QAbstractItemModel(parent), m_rootItem(new RootItem())
{
setObjectName(QSL("FeedsModel")); setObjectName(QSL("FeedsModel"));
// Create root item. // Create root item.
m_rootItem = new RootItem();
// : Name of root item of feed list which can be seen in feed add/edit dialog. // : Name of root item of feed list which can be seen in feed add/edit dialog.
m_rootItem->setTitle(tr("Root")); m_rootItem->setTitle(tr("Root"));

View File

@ -11,7 +11,6 @@
#include <QHostInfo> #include <QHostInfo>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QProcess>
FilterUtils::FilterUtils(QObject* parent) : QObject(parent) {} FilterUtils::FilterUtils(QObject* parent) : QObject(parent) {}

View File

@ -10,9 +10,6 @@
#include <QDebug> #include <QDebug>
#include <QFlags> #include <QFlags>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QUrl> #include <QUrl>
#include <QVariant> #include <QVariant>
#include <QVector> #include <QVector>

View File

@ -3,7 +3,6 @@
#include "core/messagefilter.h" #include "core/messagefilter.h"
#include "core/filterutils.h" #include "core/filterutils.h"
#include "core/message.h"
#include "exceptions/filteringexception.h" #include "exceptions/filteringexception.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"

View File

@ -2,8 +2,6 @@
#include "core/messagesmodelcache.h" #include "core/messagesmodelcache.h"
#include "miscellaneous/textfactory.h"
MessagesModelCache::MessagesModelCache(QObject* parent) : QObject(parent) {} MessagesModelCache::MessagesModelCache(QObject* parent) : QObject(parent) {}
void MessagesModelCache::setData(const QModelIndex& index, const QVariant& value, const QSqlRecord& record) { void MessagesModelCache::setData(const QModelIndex& index, const QVariant& value, const QSqlRecord& record) {

View File

@ -11,8 +11,7 @@
#include <QSqlError> #include <QSqlError>
#include <QSqlQuery> #include <QSqlQuery>
DatabaseDriver::DatabaseDriver(QObject* parent) : QObject(parent) DatabaseDriver::DatabaseDriver(QObject* parent) : QObject(parent) {}
{}
void DatabaseDriver::updateDatabaseSchema(QSqlQuery& query, void DatabaseDriver::updateDatabaseSchema(QSqlQuery& query,
int source_db_schema_version, int source_db_schema_version,

View File

@ -13,8 +13,6 @@
#include <QDir> #include <QDir>
#include <QSqlDriver> #include <QSqlDriver>
#include <QSqlError>
#include <QSqlField>
#include <QSqlQuery> #include <QSqlQuery>
#include <QSqlResult> #include <QSqlResult>
#include <QVariant> #include <QVariant>

View File

@ -3,7 +3,6 @@
#include "database/sqlitedriver.h" #include "database/sqlitedriver.h"
#include "exceptions/applicationexception.h" #include "exceptions/applicationexception.h"
#include "exceptions/ioexception.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include <QDir> #include <QDir>

View File

@ -4,7 +4,6 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "dynamic-shortcuts/shortcutcatcher.h" #include "dynamic-shortcuts/shortcutcatcher.h"
#include "gui/reusable/squeezelabel.h"
#include <QAction> #include <QAction>
#include <QGridLayout> #include <QGridLayout>

View File

@ -14,6 +14,7 @@
#include "services/abstract/label.h" #include "services/abstract/label.h"
#include "services/abstract/labelsnode.h" #include "services/abstract/labelsnode.h"
#include "services/abstract/serviceroot.h" #include "services/abstract/serviceroot.h"
#include "services/gmail/gui/emailpreviewer.h"
#include <QCheckBox> #include <QCheckBox>
#include <QGridLayout> #include <QGridLayout>
@ -141,7 +142,7 @@ void MessagePreviewer::loadMessage(const Message& message, RootItem* root) {
} }
m_viewerLayout->setCurrentIndex(1); m_viewerLayout->setCurrentIndex(1);
custom_previewer->loadMessage(message, m_root); custom_previewer->loadMessage(message, root);
} }
else { else {
ensureDefaultBrowserVisible(); ensureDefaultBrowserVisible();

View File

@ -9,7 +9,6 @@
#include "gui/reusable/locationlineedit.h" #include "gui/reusable/locationlineedit.h"
#include "gui/reusable/searchtextwidget.h" #include "gui/reusable/searchtextwidget.h"
#include "gui/tabwidget.h" #include "gui/tabwidget.h"
#include "gui/webviewers/litehtml/litehtmlviewer.h" // QLiteHtml-based web browsing.
#include "gui/webviewers/webviewer.h" #include "gui/webviewers/webviewer.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
@ -18,10 +17,6 @@
#include "network-web/webfactory.h" #include "network-web/webfactory.h"
#include "services/abstract/serviceroot.h" #include "services/abstract/serviceroot.h"
#if defined(USE_WEBENGINE)
#include "gui/webviewers/webengine/webengineviewer.h" // WebEngine-based web browsing.
#endif
#include <QKeyEvent> #include <QKeyEvent>
#include <QScrollBar> #include <QScrollBar>
#include <QTimer> #include <QTimer>
@ -43,16 +38,8 @@ WebBrowser::WebBrowser(WebViewer* viewer, QWidget* parent) : TabContent(parent),
tr("View website in reader mode"), tr("View website in reader mode"),
this)) { this)) {
if (m_webView == nullptr) { if (m_webView == nullptr) {
#if !defined(USE_WEBENGINE) m_webView = qApp->createWebView();
m_webView = new LiteHtmlViewer(this); dynamic_cast<QWidget*>(m_webView)->setParent(this);
#else
if (qApp->forcedNoWebEngine()) {
m_webView = new LiteHtmlViewer(this);
}
else {
m_webView = new WebEngineViewer(this);
}
#endif
} }
// Initialize the components and layout. // Initialize the components and layout.
@ -100,6 +87,10 @@ void WebBrowser::loadUrl(const QUrl& url) {
} }
} }
void WebBrowser::setHtml(const QString& html, const QUrl& base_url) {
m_webView->setHtml(html, base_url);
}
WebBrowser::~WebBrowser() { WebBrowser::~WebBrowser() {
// Delete members. Do not use scoped pointers here. // Delete members. Do not use scoped pointers here.
delete m_layout; delete m_layout;

View File

@ -10,6 +10,7 @@
#include <QPointer> #include <QPointer>
#include <QToolBar> #include <QToolBar>
#include <QUrl>
class QToolButton; class QToolButton;
class QVBoxLayout; class QVBoxLayout;
@ -46,6 +47,7 @@ class WebBrowser : public TabContent {
void clear(bool also_hide); void clear(bool also_hide);
void loadUrl(const QString& url); void loadUrl(const QString& url);
void loadUrl(const QUrl& url); void loadUrl(const QUrl& url);
void setHtml(const QString& html, const QUrl& base_url = {});
void loadMessages(const QList<Message>& messages, RootItem* root); void loadMessages(const QList<Message>& messages, RootItem* root);
void setNavigationBarVisible(bool visible); void setNavigationBarVisible(bool visible);

View File

@ -3,12 +3,15 @@
#include "core/message.h" #include "core/message.h"
#include <QUrl>
class WebBrowser; class WebBrowser;
class RootItem; class RootItem;
// Interface for web/article viewers. // Interface for web/article viewers.
class WebViewer { class WebViewer {
public: public:
virtual ~WebViewer();
// Performs necessary steps to make viewer work with browser. // Performs necessary steps to make viewer work with browser.
// NOTE: Each implementor must do this in this method: // NOTE: Each implementor must do this in this method:
@ -56,4 +59,6 @@ class WebViewer {
virtual void setZoomFactor(qreal zoom_factor) = 0; virtual void setZoomFactor(qreal zoom_factor) = 0;
}; };
inline WebViewer::~WebViewer() {}
#endif // WEBVIEWER_H #endif // WEBVIEWER_H

View File

@ -11,11 +11,14 @@
#include "gui/feedsview.h" #include "gui/feedsview.h"
#include "gui/messagebox.h" #include "gui/messagebox.h"
#include "gui/toolbars/statusbar.h" #include "gui/toolbars/statusbar.h"
#include "gui/webviewers/litehtml/litehtmlviewer.h" // QLiteHtml-based web browsing.
#include "miscellaneous/feedreader.h" #include "miscellaneous/feedreader.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/iofactory.h" #include "miscellaneous/iofactory.h"
#include "miscellaneous/mutex.h" #include "miscellaneous/mutex.h"
#include "miscellaneous/notificationfactory.h" #include "miscellaneous/notificationfactory.h"
#include "network-web/adblock/adblockicon.h"
#include "network-web/adblock/adblockmanager.h"
#include "network-web/webfactory.h" #include "network-web/webfactory.h"
#include "services/abstract/serviceroot.h" #include "services/abstract/serviceroot.h"
#include "services/owncloud/owncloudserviceentrypoint.h" #include "services/owncloud/owncloudserviceentrypoint.h"
@ -38,10 +41,8 @@
#include <QDBusMessage> #include <QDBusMessage>
#endif #endif
#include "network-web/adblock/adblockicon.h"
#include "network-web/adblock/adblockmanager.h"
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
#include "gui/webviewers/webengine/webengineviewer.h" // WebEngine-based web browsing.
#include "network-web/webengine/networkurlinterceptor.h" #include "network-web/webengine/networkurlinterceptor.h"
#if QT_VERSION_MAJOR == 6 #if QT_VERSION_MAJOR == 6
@ -612,6 +613,19 @@ void Application::showGuiMessage(Notification::Event event,
} }
} }
WebViewer* Application::createWebView() {
#if !defined(USE_WEBENGINE)
return new LiteHtmlViewer();
#else
if (forcedNoWebEngine()) {
return new LiteHtmlViewer();
}
else {
return new WebEngineViewer();
}
#endif
}
void Application::onCommitData(QSessionManager& manager) { void Application::onCommitData(QSessionManager& manager) {
qDebugNN << LOGSEC_CORE << "OS asked application to commit its data."; qDebugNN << LOGSEC_CORE << "OS asked application to commit its data.";

View File

@ -43,6 +43,7 @@ class QWebEngineDownloadItem;
class WebFactory; class WebFactory;
class NotificationFactory; class NotificationFactory;
class WebViewer;
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
struct ITaskbarList4; struct ITaskbarList4;
@ -160,6 +161,8 @@ class RSSGUARD_DLLSPEC Application : public SingleApplication {
const GuiAction& action = {}, const GuiAction& action = {},
QWidget* parent = nullptr); QWidget* parent = nullptr);
WebViewer* createWebView();
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
bool forcedNoWebEngine() const; bool forcedNoWebEngine() const;
#endif #endif

View File

@ -3,3 +3,5 @@
#include "services/abstract/gui/custommessagepreviewer.h" #include "services/abstract/gui/custommessagepreviewer.h"
CustomMessagePreviewer::CustomMessagePreviewer(QWidget* parent) : QWidget{parent} {} CustomMessagePreviewer::CustomMessagePreviewer(QWidget* parent) : QWidget{parent} {}
CustomMessagePreviewer::~CustomMessagePreviewer() {}

View File

@ -14,6 +14,7 @@ class CustomMessagePreviewer : public QWidget {
public: public:
explicit CustomMessagePreviewer(QWidget* parent = nullptr); explicit CustomMessagePreviewer(QWidget* parent = nullptr);
virtual ~CustomMessagePreviewer();
public: public:

View File

@ -1,13 +1,34 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/gmail/gui/emailpreviewer.h" #include "services/gmail/gui/emailpreviewer.h"
EmailPreviewer::EmailPreviewer(QWidget* parent) : CustomMessagePreviewer(parent) { #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
EmailPreviewer::EmailPreviewer(QWidget* parent) : CustomMessagePreviewer(parent), m_webView(new WebBrowser(nullptr, this)) {
m_ui.setupUi(this); m_ui.setupUi(this);
m_ui.m_mainLayout->addWidget(dynamic_cast<QWidget*>(m_webView.data()), 3, 0, 1, -1);
m_ui.m_btnAttachments->setIcon(qApp->icons()->fromTheme(QSL("mail-attachment")));
m_ui.m_btnForward->setIcon(qApp->icons()->fromTheme(QSL("mail-forward")));
m_ui.m_btnReply->setIcon(qApp->icons()->fromTheme(QSL("mail-reply-sender")));
m_webView->setNavigationBarVisible(false);
} }
EmailPreviewer::~EmailPreviewer() { EmailPreviewer::~EmailPreviewer() {
qDebugNN << LOGSEC_GMAIL << "Email previewer destroyed."; qDebugNN << LOGSEC_GMAIL << "Email previewer destroyed.";
} }
void EmailPreviewer::clear() {} void EmailPreviewer::clear() {
m_webView->clear(false);
}
void EmailPreviewer::loadMessage(const Message& msg, RootItem* selected_item) {} void EmailPreviewer::loadMessage(const Message& msg, RootItem* selected_item) {
m_webView->setHtml(msg.m_contents);
m_ui.m_tbFrom->setText(msg.m_author);
m_ui.m_tbSubject->setText(msg.m_title);
// TODO: todo
m_ui.m_tbTo->setText(QSL("-"));
}

View File

@ -1,8 +1,12 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef EMAILPREVIEWER_H #ifndef EMAILPREVIEWER_H
#define EMAILPREVIEWER_H #define EMAILPREVIEWER_H
#include "services/abstract/gui/custommessagepreviewer.h" #include "services/abstract/gui/custommessagepreviewer.h"
#include "gui/webbrowser.h"
#include "ui_emailpreviewer.h" #include "ui_emailpreviewer.h"
class EmailPreviewer : public CustomMessagePreviewer { class EmailPreviewer : public CustomMessagePreviewer {
@ -17,6 +21,7 @@ class EmailPreviewer : public CustomMessagePreviewer {
private: private:
Ui::EmailPreviewer m_ui; Ui::EmailPreviewer m_ui;
QScopedPointer<WebBrowser> m_webView;
}; };
#endif // EMAILPREVIEWER_H #endif // EMAILPREVIEWER_H

View File

@ -6,27 +6,127 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>518</width>
<height>300</height> <height>378</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QGridLayout" name="m_mainLayout">
<item row="2" column="1">
<widget class="QLineEdit" name="m_tbSubject">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>80</x>
<y>90</y>
<width>49</width>
<height>16</height>
</rect>
</property>
<property name="text"> <property name="text">
<string>test</string> <string>From</string>
</property>
<property name="buddy">
<cstring>m_tbFrom</cstring>
</property> </property>
</widget> </widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="m_tbFrom">
<property name="readOnly">
<bool>true</bool>
</property>
</widget> </widget>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="m_btnAttachments">
<property name="text">
<string>&amp;Attachments</string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="arrowType">
<enum>Qt::DownArrow</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_btnReply">
<property name="text">
<string>&amp;Reply</string>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_btnForward">
<property name="text">
<string>&amp;Forward</string>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Subject</string>
</property>
<property name="buddy">
<cstring>m_tbSubject</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="m_tbTo">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>To</string>
</property>
<property name="buddy">
<cstring>m_tbTo</cstring>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>m_tbFrom</tabstop>
<tabstop>m_tbTo</tabstop>
<tabstop>m_tbSubject</tabstop>
<tabstop>m_btnReply</tabstop>
<tabstop>m_btnForward</tabstop>
</tabstops>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>