diff --git a/app/README.references.txt b/app/README.references.txt index 6d0d86c..98a57a7 100644 --- a/app/README.references.txt +++ b/app/README.references.txt @@ -1,3 +1,4 @@ Native messaging https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging + diff --git a/app/SysTray-X/SysTray-X.pro b/app/SysTray-X/SysTray-X.pro index 4792009..38ab0f3 100644 --- a/app/SysTray-X/SysTray-X.pro +++ b/app/SysTray-X/SysTray-X.pro @@ -125,15 +125,24 @@ message("Version: "$$VERSION_MAJOR"."$$VERSION_MINOR"."$$VERSION_PATCH) SOURCES += \ main.cpp \ - mainwindow.cpp \ - systrayxlink.cpp + systrayxlink.cpp \ + systrayxicon.cpp \ + systrayx.cpp \ + debugwidget.cpp \ + preferencesdialog.cpp \ + preferences.cpp HEADERS += \ - mainwindow.h \ - systrayxlink.h + systrayxlink.h \ + systrayxicon.h \ + systrayx.h \ + debugwidget.h \ + preferencesdialog.h \ + preferences.h FORMS += \ - mainwindow.ui + debugwidget.ui \ + preferences.ui # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin diff --git a/app/SysTray-X/SysTray-X.qrc b/app/SysTray-X/SysTray-X.qrc index 6fafe49..37b9c8d 100644 --- a/app/SysTray-X/SysTray-X.qrc +++ b/app/SysTray-X/SysTray-X.qrc @@ -1,5 +1,6 @@ files/icons/SysTray-X.png + files/icons/blank-icon.png diff --git a/app/SysTray-X/debugwidget.cpp b/app/SysTray-X/debugwidget.cpp new file mode 100644 index 0000000..836a91e --- /dev/null +++ b/app/SysTray-X/debugwidget.cpp @@ -0,0 +1,130 @@ +#include "debugwidget.h" +#include "ui_debugwidget.h" + +/* + * Local includes + */ +#include "preferences.h" + +/* + * Qt includes + */ + + +/* + * Constructor + */ +DebugWidget::DebugWidget( Preferences *pref, QWidget *parent ) : QWidget( parent ), m_ui( new Ui::DebugWidget ) +{ + m_ui->setupUi( this ); + + /* + * Store the preferences + */ + m_pref = pref; +} + + +/* + * Set the debug message + */ +void DebugWidget::setDebugMessage( QString message ) +{ + m_ui->messageLabel->setText( message ); +} + + +/* + * Set the raw data length + */ +void DebugWidget::setRawDataLength( int length ) +{ + m_ui->rawDataLengthLabel->setText( QString::number( length ) ); +} + + +/* + * Set the raw received message + */ +void DebugWidget::setErrorDataMessage( const QString &message ) +{ + m_ui->rawDataLabel->setText( message ); +} + + +/* + * Set the number of unread mail + */ +void DebugWidget::setUnreadMail( int unread ) +{ + m_ui->unreadMailLabel->setText( QString::number( unread ) ); +} + + +/* + * Set the link error message + */ +void DebugWidget::setError( const QString &error ) +{ + m_ui->errorLabel->setText( error ); +} + + +/* + * Handle a debug state change signal + */ +void DebugWidget::slotDebugChange() +{ + this->setVisible( m_pref->getDebug() ); +} + + +/* + * Handle a debug message signal + */ +void DebugWidget::slotDebugMessage( QString message ) +{ + setDebugMessage( message ); +} + + +/* + * Handle received message length + */ +void DebugWidget::slotReceivedMessageLength( qint32 msglen ) +{ + setRawDataLength( msglen ); +} + + +/* + * Display received message + */ +void DebugWidget::slotReceivedMessage( QByteArray message ) +{ + setErrorDataMessage( QString( message ) ); + + /* + * Reply + */ +// QByteArray reply = QString( "\"Hallo other world!\"" ).toUtf8(); +// emit signalWriteMessage( reply ); +} + + +/* + * Handle unread mail signal + */ +void DebugWidget::slotUnreadMail( int unread_mail ) +{ + setUnreadMail( unread_mail ); +} + + +/* + * Handle a receive error + */ +void DebugWidget::slotReceiveError( QString error ) +{ + setError( error ); +} diff --git a/app/SysTray-X/debugwidget.h b/app/SysTray-X/debugwidget.h new file mode 100644 index 0000000..a4aae96 --- /dev/null +++ b/app/SysTray-X/debugwidget.h @@ -0,0 +1,140 @@ +#ifndef DEBUGWIDGET_H +#define DEBUGWIDGET_H + +/* + * Local includes + */ + +/* + * Qt includes + */ +#include + +/* + * Predefines + */ +class Preferences; + +/* + * Namespace + */ +namespace Ui { + class DebugWidget; +} + +/** + * @brief The DebugWidget class + */ +class DebugWidget : public QWidget +{ + Q_OBJECT + + public: + + /** + * @brief DebugWidget. Constructor. + * + * @param parent My parent. + */ + explicit DebugWidget( Preferences *pref, QWidget *parent = nullptr ); + + /** + * @brief setDebugMessage. Display a debug message. + * + * @param message The message to display. + */ + void setDebugMessage( QString message ); + + /** + * @brief setRawDataLength. Display the error data length. + * + * @param length The raw data length. + */ + void setRawDataLength( int length ); + + /** + * @brief setRswDataMessage. Display the raw data. + * + * @param message The raw data messsage. + */ + void setErrorDataMessage( const QString &message ); + + /** + * @brief setUnreadMail. Set the number of unread mails. + * + * @param unread The number of unread mails. + */ + void setUnreadMail( int unread ); + + /** + * @brief setError. Set the error message. + * + * @param error The error message. + */ + void setError( const QString &error ); + + signals: + + /** + * @brief signalWriteMessage + * + * @param message + */ + void signalWriteMessage( QByteArray message ); + + public slots: + + /** + * @brief slotDebugChange. The debug state changed. + */ + void slotDebugChange(); + + /** + * @brief slotReceivedMessageLength + * + * @param msglen + */ + void slotDebugMessage( QString message ); + + /** + * @brief slotReceivedMessageLength + * + * @param msglen + */ + void slotReceivedMessageLength( qint32 msglen ); + + /** + * @brief slotReceivedMessage + * + * @param message + */ + void slotReceivedMessage( QByteArray message ); + + /** + * @brief slotSetUnreadMail. Slot for handling unread mail signals. + * + * @param unread_mail The number of unread mails. + */ + void slotUnreadMail( int unread_mail ); + + /** + * @brief slotReceiveError. Handle receive error signal. + * + * @param error Error message. + */ + void slotReceiveError( QString error ); + + private: + + /** + * @brief m_ui. Pointer to the widget. + */ + Ui::DebugWidget *m_ui; + + /** + * @brief m_pref. Pointer to ther preferences. + */ + Preferences *m_pref; +}; + +#endif // DEBUGWIDGET_H diff --git a/app/SysTray-X/debugwidget.ui b/app/SysTray-X/debugwidget.ui new file mode 100644 index 0000000..2cd02d9 --- /dev/null +++ b/app/SysTray-X/debugwidget.ui @@ -0,0 +1,99 @@ + + + DebugWidget + + + + 0 + 0 + 400 + 300 + + + + SysTray-X Debug + + + + + 10 + 10 + 381 + 281 + + + + + + + 0 + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Unread mail: + + + + + + + + + + + + + + + + diff --git a/app/SysTray-X/files/icons/LICENSE b/app/SysTray-X/files/icons/LICENSE index c4e7bdc..b47ed98 100644 --- a/app/SysTray-X/files/icons/LICENSE +++ b/app/SysTray-X/files/icons/LICENSE @@ -1 +1 @@ -The icon used here is taken from the "Miscellany Web icons" set by Maria & Guillem (https://www.iconfinder.com/andromina), and is used under the Creative Commons (Attribution 3.0 Unported) license. +The SysTray-X / mail icon used here is taken from the "Miscellany Web icons" set by Maria & Guillem (https://www.iconfinder.com/andromina), and is used under the Creative Commons (Attribution 3.0 Unported) license. diff --git a/app/SysTray-X/files/icons/blank-icon.png b/app/SysTray-X/files/icons/blank-icon.png new file mode 100644 index 0000000..be5c8fa Binary files /dev/null and b/app/SysTray-X/files/icons/blank-icon.png differ diff --git a/app/SysTray-X/main.cpp b/app/SysTray-X/main.cpp index b48f94e..2c269b8 100644 --- a/app/SysTray-X/main.cpp +++ b/app/SysTray-X/main.cpp @@ -1,11 +1,17 @@ -#include "mainwindow.h" +/* + * Local includes + */ +#include "systrayx.h" + +/* + * Qt includes + */ #include int main(int argc, char *argv[]) { QApplication a(argc, argv); - MainWindow w; - w.show(); + SysTrayX systrayx; return a.exec(); } diff --git a/app/SysTray-X/mainwindow.cpp b/app/SysTray-X/mainwindow.cpp deleted file mode 100644 index b4e8bc6..0000000 --- a/app/SysTray-X/mainwindow.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "mainwindow.h" -#include "ui_mainwindow.h" - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow) -{ - ui->setupUi(this); - - connect( &m_systray_x_link, &SysTrayXLink::signalReceivedMessageLength, this, &MainWindow::slotReceivedMessageLength ); - connect( &m_systray_x_link, &SysTrayXLink::signalReceivedMessage, this, &MainWindow::slotReceivedMessage ); - - connect( this, &MainWindow::signalWriteMessage, &m_systray_x_link, &SysTrayXLink::slotLinkWrite ); -} - - -MainWindow::~MainWindow() -{ - delete ui; -} - - -void MainWindow::slotReceivedMessageLength( qint32 msglen ) -{ - ui->label_length->setText(QString::number( msglen ) ); -} - - -void MainWindow::slotReceivedMessage( QByteArray message ) -{ - ui->label_message->setText( QString::fromStdString( message.toStdString() ) ); - - /* - * Reply - */ - QByteArray reply = QString( "\"Hallo other world!\"" ).toUtf8(); - emit signalWriteMessage( reply ); -} diff --git a/app/SysTray-X/mainwindow.h b/app/SysTray-X/mainwindow.h deleted file mode 100644 index 6dd3ed0..0000000 --- a/app/SysTray-X/mainwindow.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -/* - * Local includes - */ -#include "systrayxlink.h" - -/* - * Qt includes - */ -#include -#include - - - -namespace Ui { - class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - - public: - explicit MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - - private slots: - - /** - * @brief slotReceivedMessageLength - * - * @param msglen - */ - void slotReceivedMessageLength( qint32 msglen ); - - /** - * @brief slotReceivedMessage - * - * @param message - */ - void slotReceivedMessage( QByteArray message ); - - signals: - - /** - * @brief signalWriteMessage - * - * @param message - */ - void signalWriteMessage( QByteArray message ); - - private: - Ui::MainWindow *ui; - - SysTrayXLink m_systray_x_link; -}; - -#endif // MAINWINDOW_H diff --git a/app/SysTray-X/mainwindow.ui b/app/SysTray-X/mainwindow.ui deleted file mode 100644 index 148e884..0000000 --- a/app/SysTray-X/mainwindow.ui +++ /dev/null @@ -1,67 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 400 - 300 - - - - MainWindow - - - - - - 50 - 10 - 271 - 51 - - - - Data here - - - - - - 50 - 80 - 271 - 51 - - - - Data here - - - - - - - 0 - 0 - 400 - 30 - - - - - - TopToolBarArea - - - false - - - - - - - - diff --git a/app/SysTray-X/preferences.cpp b/app/SysTray-X/preferences.cpp new file mode 100644 index 0000000..0f52a96 --- /dev/null +++ b/app/SysTray-X/preferences.cpp @@ -0,0 +1,137 @@ +#include "preferences.h" + + +/** + * @brief Preferences. Constructor. + */ +Preferences::Preferences( QObject *parent ) : QObject( parent ) +{ + /* + * Initialize + */ + m_app_pref_changed = false; + + m_icon_type = PREF_BLANK_ICON; + m_icon_mime = "image/png"; + m_icon_data = QByteArray(); + + m_debug = false; +} + + +/* + * Get the icon type. + */ +Preferences::IconType Preferences::getIconType() const +{ + return m_icon_type; +} + + +/* + * Get the icon mime. + */ +bool Preferences::getAppPrefChanged() const +{ + return m_app_pref_changed; +} + + +/* + * Control the sending of preferences changes to the add-on + */ +void Preferences::setAppPrefChanged( bool state ) +{ + if( m_app_pref_changed != state ) + { + m_app_pref_changed = state; + } +} + + +/* + * Set the icon type. + */ +void Preferences::setIconType( IconType icon_type ) +{ + if( m_icon_type != icon_type) + { + m_icon_type = icon_type; + + /* + * Tell the world the new preference + */ + emit signalIconTypeChange(); + } +} + + +/* + * Get the icon mime. + */ +const QString& Preferences::getIconMime() const +{ + return m_icon_mime; +} + + +/* + * Set the icon mime. + */ +void Preferences::setIconMime( const QString& icon_mime ) +{ + m_icon_mime = icon_mime; +} + + +/* + * Get the icon data. + */ +const QByteArray& Preferences::getIconData() const +{ + return m_icon_data; +} + + +/* + * Set the icon data. + */ +void Preferences::setIconData( const QByteArray& icon_data ) +{ + + if( m_icon_data != icon_data ) + { + m_icon_data = icon_data; + + /* + * Tell the world the new preference + */ + emit signalIconDataChange(); + } +} + + +/* + * Get the icon data. + */ +bool Preferences::getDebug() const +{ + return m_debug; +} + + +/* + * Set the icon data. + */ +void Preferences::setDebug( bool state ) +{ + if( m_debug != state ) + { + m_debug = state; + + /* + * Tell the world the new preference + */ + emit signalDebugChange(); + } +} diff --git a/app/SysTray-X/preferences.h b/app/SysTray-X/preferences.h new file mode 100644 index 0000000..c7460f9 --- /dev/null +++ b/app/SysTray-X/preferences.h @@ -0,0 +1,155 @@ +#ifndef PREFERENCES_H +#define PREFERENCES_H + +/* + * Local includes + */ + +/* + * Qt includes + */ +#include +#include +#include + +/** + * @brief The Preferences class. Class to hold the preferences. + */ +class Preferences : public QObject +{ + Q_OBJECT + + public: + + /* + * Icon types + */ + enum IconType { + PREF_BLANK_ICON = 0, + PREF_NEWMAIL_ICON, + PREF_CUSTOM_ICON + }; + + public: + + /** + * @brief Preferences. Constructor. + */ + Preferences( QObject *parent = nullptr ); + + /** + * @brief getAppPrefChanged. Control for sending changes to the add-on. + * + * @return The state + */ + bool getAppPrefChanged() const; + + /** + * @brief setAppPrefChanged. Control for sending changes to the add-on. + * + * @param state The state + */ + void setAppPrefChanged( bool state ); + + /** + * @brief getIconType. Get the icon type. + * + * @return The icon type. + */ + IconType getIconType() const; + + /** + * @brief setIconType. Set the icon type. + * + * @param The icon type. + */ + void setIconType( IconType icon_type ); + + /** + * @brief getIconMime. Get the icon mime. + * + * @return The icon mime. + */ + const QString& getIconMime() const; + + /** + * @brief setIconMime. Set the icon mime. + * + * @param The icon mime. + */ + void setIconMime( const QString& icon_mime ); + + /** + * @brief getIconData. Get the icon data. + * + * @return The icon data. + */ + const QByteArray& getIconData() const; + + /** + * @brief setIconData. Set the icon data. + * + * @param The icon data. + */ + void setIconData( const QByteArray& icon_data ); + + /** + * @brief getDebug. Get the debug windows state. + * + * @return The state. + */ + bool getDebug() const; + + /** + * @brief setDebug. Set the debug windows state. + * + * @param The state. + */ + void setDebug( bool state ); + + signals: + + /** + * @brief signalIconTypeChange. Signal a icon type change. + */ + void signalIconTypeChange(); + + /** + * @brief signalIconDataChange. Signal a icon data change. + */ + void signalIconDataChange(); + + /** + * @brief signalDebugChange. Signal a debug state change. + */ + void signalDebugChange(); + + private: + + /** + * @brief m_app_pref_changed. Control for sending changes to the add-on. + */ + bool m_app_pref_changed; + + /** + * @brief m_icon_type. Selected icon type. + */ + IconType m_icon_type; + + /** + * @brief m_icon_mime. Selected icon mime. + */ + QString m_icon_mime; + + /** + * @brief m_icon_data. Binary data icon image. + */ + QByteArray m_icon_data; + + /** + * @brief m_debug. Display debug window. + */ + bool m_debug; +}; + +#endif // PREFERENCES_H diff --git a/app/SysTray-X/preferences.ui b/app/SysTray-X/preferences.ui new file mode 100644 index 0000000..832bb1c --- /dev/null +++ b/app/SysTray-X/preferences.ui @@ -0,0 +1,207 @@ + + + PreferencesDialog + + + + 0 + 0 + 553 + 544 + + + + SysTray-X Preferences + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Mail notification icon + + + + + + + + QLayout::SetFixedSize + + + + + Blank icon + + + true + + + iconTypeGroup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QLayout::SetFixedSize + + + + + New mail icon + + + iconTypeGroup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QLayout::SetMaximumSize + + + + + Custom icon + + + iconTypeGroup + + + + + + + + + + + + + + Choose + + + false + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Display debug window + + + + + + + + + buttonBox + rejected() + PreferencesDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + + + + diff --git a/app/SysTray-X/preferencesdialog.cpp b/app/SysTray-X/preferencesdialog.cpp new file mode 100644 index 0000000..03d9b4f --- /dev/null +++ b/app/SysTray-X/preferencesdialog.cpp @@ -0,0 +1,191 @@ +#include "preferencesdialog.h" +#include "ui_preferences.h" + +/* + * Local includes + */ +#include "systrayxlink.h" + +/* + * Qt includes + */ +#include +#include +#include +#include +#include + +/* + * Constructor + */ +PreferencesDialog::PreferencesDialog( SysTrayXLink *link, Preferences *pref, QWidget *parent ) : QDialog( parent ), m_ui( new Ui::PreferencesDialog ) +{ + m_ui->setupUi( this ); + + /* + * Store link adn preferences + */ + m_link = link; + m_pref = pref; + + /* + * Set button Ids + */ + m_ui->iconTypeGroup->setId( m_ui->blankRadioButton, Preferences::PREF_BLANK_ICON ); + m_ui->iconTypeGroup->setId( m_ui->newMailButton, Preferences::PREF_NEWMAIL_ICON ); + m_ui->iconTypeGroup->setId( m_ui->customRadioButton, Preferences::PREF_CUSTOM_ICON ); + + /* + * Set defaults + */ + m_tmp_icon_data = QByteArray(); + m_tmp_icon_mime = QString(); + + /* + * Signals and slots + */ + connect( m_ui->chooseCustomButton, &QPushButton::clicked, this, &PreferencesDialog::slotFileSelect ); + connect( m_ui->buttonBox, &QDialogButtonBox::accepted, this, &PreferencesDialog::slotAccept ); +} + + +/* + * Set the debug state + */ +void PreferencesDialog::setDebug( bool state ) +{ + m_ui->debugWindowCheckBox->setChecked( state ); +} + + +/* + * Set the icon type + */ +void PreferencesDialog::setIconType( Preferences::IconType icon_type ) +{ + ( m_ui->iconTypeGroup->button( icon_type ) )->setChecked( true ); +} + +/* + * Set the icon + */ +void PreferencesDialog::setIcon( const QString& icon_mime, const QByteArray& icon ) +{ + /* + * Store the new icon + */ + m_tmp_icon_mime = icon_mime; + m_tmp_icon_data = icon; + + /* + * Display the new icon + */ + setIcon(); +} + + +/* + * Set the icon + */ +void PreferencesDialog::setIcon() +{ + /* + * Convert data to pixmap + */ + QPixmap pixmap; + pixmap.loadFromData( m_tmp_icon_data ); + + /* + * Display the icon + */ + m_ui->imageLabel->setPixmap( pixmap.scaledToHeight( m_ui->chooseCustomButton->size().height() ) ); +} + + +/* + * Handle the accept signal + */ +void PreferencesDialog::slotAccept() +{ + /* + * Settings changed by app + */ + m_pref->setAppPrefChanged( true ); + + /* + * Get all the selected values and store them in the preferences + */ + m_pref->setIconType( static_cast< Preferences::IconType >( m_ui->iconTypeGroup->checkedId() ) ); + m_pref->setIconMime( m_tmp_icon_mime ); + m_pref->setIconData( m_tmp_icon_data ); + + m_pref->setDebug( m_ui->debugWindowCheckBox->isChecked() ); + + /* + * Settings changed by app + */ + m_pref->setAppPrefChanged( false ); + + /* + * Tell the base + */ + QDialog::accept(); +} + + +/* + * Handle the choose button + */ +void PreferencesDialog::slotFileSelect() +{ + QFileDialog file_dialog( this, tr( "Open Image" ), "", tr( "Image Files (*.png *.jpg *.bmp)" ) ); + + if( file_dialog.exec() ) + { + QFile file( file_dialog.selectedFiles()[ 0 ] ); + file.open( QIODevice::ReadOnly ); + m_tmp_icon_data = file.readAll(); + file.close(); + + QMimeType type = QMimeDatabase().mimeTypeForData( m_tmp_icon_data ); + m_tmp_icon_mime = type.name(); + + /* + * Display the icon + */ + setIcon(); + } +} + + +/* + * Handle the debug change signal + */ +void PreferencesDialog::slotDebugChange() +{ + setDebug( m_pref->getDebug() ); +} + + +/* + * Handle the icon type change signal + */ +void PreferencesDialog::slotIconTypeChange() +{ + setIconType( m_pref->getIconType() ); +} + + +/* + * Handle the icon data change signal + */ +void PreferencesDialog::slotIconDataChange() +{ + m_tmp_icon_mime = m_pref->getIconMime(); + m_tmp_icon_data = m_pref->getIconData(); + + /* + * Display the icon + */ + setIcon(); +} diff --git a/app/SysTray-X/preferencesdialog.h b/app/SysTray-X/preferencesdialog.h new file mode 100644 index 0000000..1a90513 --- /dev/null +++ b/app/SysTray-X/preferencesdialog.h @@ -0,0 +1,143 @@ +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +/* + * Local includes + */ +#include "preferences.h" + +/* + * Qt includes + */ +#include +#include + +/* + * Predefines + */ +class SysTrayXLink; + +/* + * Namespace + */ +namespace Ui { + class PreferencesDialog; +} + + +/** + * @brief The PreferencesDialog class. Handles the preferences. + */ +class PreferencesDialog : public QDialog +{ + Q_OBJECT + + public: + + /** + * @brief PreferencesDialog + */ + PreferencesDialog( SysTrayXLink *link, Preferences *pref, QWidget *parent = nullptr ); + + private: + + /** + * @brief setDebug. Set the debug state. + * + * @param state The state. + */ + void setDebug( bool state ); + + /** + * @brief setIconType. Set the icon type. + * + * @param icon_type The icon type. + */ + void setIconType( Preferences::IconType icon_type ); + + /** + * @brief setIcon. Set the icon. + * + * @param icon The icon mime. + * @param icon The icon data. + */ + void setIcon( const QString& icon_mime, const QByteArray& icon ); + + /** + * @brief setIcon. Set the icon. + */ + void setIcon(); + + signals: + + /** + * @brief signalDebugMessage. Signal a debug message. + * + * @param message The message. + */ + void signalDebugMessage( QString message ); + + /** + * @brief signalUpdateSysTray. Signal to update the system tray icon. + */ + void signalUpdateSysTrayIcon(); + + public slots: + + /** + * @brief slotDebugChange. Slot for handling debug change signals. + */ + void slotDebugChange(); + + /** + * @brief slotIconTypeChange. Slot for handling icon type change signals. + */ + void slotIconTypeChange(); + + /** + * @brief slotIconDataChange. Slot for handling icon data change signals. + */ + void slotIconDataChange(); + + private slots: + + /** + * @brief slotAccept. Store the preferences on the accept signal. + */ + void slotAccept(); + + /** + * @brief slotFileSelect. Handle the choose custom button click. + */ + void slotFileSelect(); + + private: + + /** + * @brief m_ui. Pointer to the dialog. + */ + Ui::PreferencesDialog *m_ui; + + /** + * @brief m_link. Pointer to the link. + */ + SysTrayXLink *m_link; + + /** + * @brief m_pref. Pointer to the preferences storage. + */ + Preferences *m_pref; + + /** + * @brief m_tmp_icon_mime. Temporary storage for icon mime. + */ + QString m_tmp_icon_mime; + + /** + * @brief m_tmp_icon_data. Temporary storage for icon data. + */ + QByteArray m_tmp_icon_data; + +}; + +#endif // PREFERENCESDIALOG_H diff --git a/app/SysTray-X/systrayx.cpp b/app/SysTray-X/systrayx.cpp new file mode 100644 index 0000000..a3a4261 --- /dev/null +++ b/app/SysTray-X/systrayx.cpp @@ -0,0 +1,193 @@ +#include "systrayx.h" + +/* + * Local includes + */ +#include "debugwidget.h" +#include "preferencesdialog.h" +#include "systrayxlink.h" +#include "systrayxicon.h" + +/* + * Qt includes + */ +#include +#include + +/* + * Constants + */ +const QString SysTrayX::JSON_PREF_REQUEST = "{\"preferences\":{}}"; + + +/* + * Constructor + */ +SysTrayX::SysTrayX( QObject *parent ) : QObject( parent ) +{ + /* + * Setup preferences storage + */ + m_preferences = new Preferences(); + + /* + * Setup the link + */ + m_link = new SysTrayXLink( m_preferences ); + + /* + * Setup preferences dialog + */ + m_pref_dialog = new PreferencesDialog( m_link, m_preferences ); + + /* + * Setup tray icon + */ + createTrayIcon(); + m_tray_icon->show(); + + /* + * Setup debug window + */ + m_debug = new DebugWidget( m_preferences ); + if( m_preferences->getDebug() ) { + m_debug->show(); + } + +// connect( m_trayIcon, &QSystemTrayIcon::messageClicked, this, &SysTrayX::messageClicked); + connect( m_tray_icon, &QSystemTrayIcon::activated, this, &SysTrayX::iconActivated); + + /* + * Connect debug link signals + */ + connect( m_link, &SysTrayXLink::signalReceivedMessageLength, m_debug, &DebugWidget::slotReceivedMessageLength ); + connect( m_link, &SysTrayXLink::signalReceivedMessage, m_debug, &DebugWidget::slotReceivedMessage ); + + connect( m_link, &SysTrayXLink::signalUnreadMail, m_debug, &DebugWidget::slotUnreadMail ); + + connect( m_link, &SysTrayXLink::signalLinkReceiveError, m_debug, &DebugWidget::slotReceiveError ); + + connect( m_debug, &DebugWidget::signalWriteMessage, m_link, &SysTrayXLink::slotLinkWrite ); + + connect( m_pref_dialog, &PreferencesDialog::signalDebugMessage, m_debug, &DebugWidget::slotDebugMessage ); + connect( m_tray_icon, &SysTrayXIcon::signalDebugMessage, m_debug, &DebugWidget::slotDebugMessage ); + connect( m_link, &SysTrayXLink::signalDebugMessage, m_debug, &DebugWidget::slotDebugMessage ); + + + /* + * Connect preferences signals + */ + connect( m_preferences, &Preferences::signalIconTypeChange, m_tray_icon, &SysTrayXIcon::slotIconTypeChange ); + connect( m_preferences, &Preferences::signalIconDataChange, m_tray_icon, &SysTrayXIcon::slotIconDataChange ); + + connect( m_preferences, &Preferences::signalIconTypeChange, m_pref_dialog, &PreferencesDialog::slotIconTypeChange ); + connect( m_preferences, &Preferences::signalIconDataChange, m_pref_dialog, &PreferencesDialog::slotIconDataChange ); + connect( m_preferences, &Preferences::signalDebugChange, m_pref_dialog, &PreferencesDialog::slotDebugChange ); + + connect( m_preferences, &Preferences::signalIconTypeChange, m_link, &SysTrayXLink::slotIconTypeChange ); + connect( m_preferences, &Preferences::signalIconDataChange, m_link, &SysTrayXLink::slotIconDataChange ); + connect( m_preferences, &Preferences::signalDebugChange, m_link, &SysTrayXLink::slotDebugChange ); + + connect( m_preferences, &Preferences::signalDebugChange, m_debug, &DebugWidget::slotDebugChange ); + + /* + * Connect link signals + */ + connect( m_link, &SysTrayXLink::signalUnreadMail, m_tray_icon, &SysTrayXIcon::slotSetUnreadMail ); + + /* + * Request preferences from add-on + */ + getPreferences(); +} + + +/* + * Send a preferences request + */ +void SysTrayX::getPreferences() +{ + /* + * Request preferences from add-on + */ + QByteArray request = QString( SysTrayX::JSON_PREF_REQUEST ).toUtf8(); + emit signalWriteMessage( request ); +} + + +/* + * Handle a click on the system tray icon + */ +void SysTrayX::iconActivated( QSystemTrayIcon::ActivationReason reason ) +{ + switch (reason) { + case QSystemTrayIcon::Trigger: + case QSystemTrayIcon::DoubleClick: + case QSystemTrayIcon::MiddleClick: + break; + default: + ; + } +} + + +/* + * Create the actions for the system tray icon menu + */ +void SysTrayX::createActions() +{ +/* + m_minimizeAction = new QAction(tr("Mi&nimize"), this); + connect( m_minimizeAction, &QAction::triggered, this, &QWidget::hide ); + + m_maximizeAction = new QAction(tr("Ma&ximize"), this); + connect( m_maximizeAction, &QAction::triggered, this, &QWidget::showMaximized ); + + m_restoreAction = new QAction(tr("&Restore"), this); + connect( m_restoreAction, &QAction::triggered, this, &QWidget::showNormal ); +*/ + + m_pref_action = new QAction(tr("&Preferences"), this); + connect( m_pref_action, &QAction::triggered, m_pref_dialog, &PreferencesDialog::showNormal ); + + m_quit_action = new QAction(tr("&Quit"), this); + connect( m_quit_action, &QAction::triggered, qApp, &QCoreApplication::quit ); + +} + + +/* + * Create the system tray icon + */ +void SysTrayX::createTrayIcon() +{ + /* + * Setup menu actions + */ + createActions(); + + /* + * Setup menu + */ + m_tray_icon_menu = new QMenu(); +// m_trayIconMenu->addAction( m_minimizeAction ); +// m_trayIconMenu->addAction( m_maximizeAction ); +// m_trayIconMenu->addAction( m_restoreAction ); + + m_tray_icon_menu->addAction( m_pref_action ); + m_tray_icon_menu->addSeparator(); + m_tray_icon_menu->addAction( m_quit_action ); + + /* + * Create system tray icon + */ + m_tray_icon = new SysTrayXIcon( m_link, m_preferences ); + m_tray_icon->setContextMenu( m_tray_icon_menu ); + + /* + * Set icon + */ + m_tray_icon->setIconMime( m_preferences->getIconMime() ); + m_tray_icon->setIconData( m_preferences->getIconData() ); + m_tray_icon->setIconType( m_preferences->getIconType() ); +} diff --git a/app/SysTray-X/systrayx.h b/app/SysTray-X/systrayx.h new file mode 100644 index 0000000..849a0a2 --- /dev/null +++ b/app/SysTray-X/systrayx.h @@ -0,0 +1,119 @@ +#ifndef SYSTRAYX_H +#define SYSTRAYX_H + +/* + * Local includes + */ +#include "ui_debugwidget.h" +#include "preferences.h" + +/* + * Qt includes + */ +#include +#include + +/* + * Predefines + */ +class QAction; + +class DebugWidget; +class PreferencesDialog; +class SysTrayXIcon; +class SysTrayXLink; + +/** + * @brief The SysTrayX class + */ +class SysTrayX : public QObject +{ + Q_OBJECT + + public: + + static const QString JSON_PREF_REQUEST; + + public: + + /** + * @brief SysTrayX. Constructor. + * + * @param parent My parent. + */ + explicit SysTrayX( QObject *parent = nullptr ); + + private: + + /** + * @brief SysTrayX::getPreferences + */ + void getPreferences(); + + /** + * @brief iconActivated + * @param reason + */ + void iconActivated( QSystemTrayIcon::ActivationReason reason ); + + /** + * @brief createTrayIcon. Create the system tray icon. + */ + void createTrayIcon(); + + /** + * @brief createActions. Create the menu actions. + */ + void createActions(); + + signals: + + /** + * @brief signalWriteMessage + * + * @param message + */ + void signalWriteMessage( QByteArray message ); + + private slots: + + private: + + /** + * @brief m_preferences. Pointer to the preferences storage. + */ + Preferences *m_preferences; + + /** + * @brief m_debug + */ + DebugWidget *m_debug; + + /** + * @brief m_link. Pointer to the link object. + */ + SysTrayXLink *m_link; + + /** + * @brief m_pref_dialog. Pointer to the preferences dialog. + */ + PreferencesDialog *m_pref_dialog; + + /** + * @brief m_tray_icon. Pointer to the system tray icon. + */ + SysTrayXIcon *m_tray_icon; + + /** + * @brief m_tray_icon_menu. Pointer to the tray icon menu. + */ + QMenu *m_tray_icon_menu; + + /** + * @brief m_xxxx_action. Pointer to the menu actions. + */ + QAction *m_pref_action; + QAction *m_quit_action; +}; + +#endif // SYSTRAYX_H diff --git a/app/SysTray-X/systrayxicon.cpp b/app/SysTray-X/systrayxicon.cpp new file mode 100644 index 0000000..b3889bc --- /dev/null +++ b/app/SysTray-X/systrayxicon.cpp @@ -0,0 +1,184 @@ +#include "systrayxicon.h" + +/* + * Local includes + */ +#include "preferences.h" + +/* + * System includes + */ +#include "systrayxlink.h" + +/* + * Qt includes + */ +#include + + +/* + * Constructor + */ +SysTrayXIcon::SysTrayXIcon( SysTrayXLink *link, Preferences *pref, QObject *parent ) : QSystemTrayIcon( QIcon(), parent ) +{ + /* + * Initialize + */ + m_link = link; + m_pref = pref; + + m_unread_mail = 0; +} + + +/* + * Set the icon type + */ +void SysTrayXIcon::setIconType( Preferences::IconType icon_type ) +{ + if( icon_type != m_icon_type ) + { + /* + * Store the new value + */ + m_icon_type = icon_type; + + /* + * Render and set a new icon in the tray + */ + renderIcon(); + } +} + + +/* + * Set the icon mime + */ +void SysTrayXIcon::setIconMime( const QString& icon_mime ) +{ + if( m_icon_mime != icon_mime ) + { + /* + * Store the new value + */ + m_icon_mime = icon_mime; + } +} + + +/* + * Set the icon type + */ +void SysTrayXIcon::setIconData( const QByteArray& icon_data ) +{ + if( m_icon_data != icon_data ) + { + /* + * Store the new value + */ + m_icon_data = icon_data; + + /* + * Render and set a new icon in the tray + */ + renderIcon(); + } +} + + +/* + * Set the number of unread mails + */ +void SysTrayXIcon::setUnreadMail( int unread_mail ) +{ + if( unread_mail != m_unread_mail ) { + + /* + * Store the new value + */ + m_unread_mail = unread_mail; + + /* + * Render and set a new icon in the tray + */ + renderIcon(); + } +} + + +/* + * Set and render the icon in the system tray + */ +void SysTrayXIcon::renderIcon() +{ + QPixmap pixmap; + + switch( m_icon_type ) + { + case Preferences::PREF_BLANK_ICON: + case Preferences::PREF_NEWMAIL_ICON: + { + pixmap = QPixmap( ":/files/icons/blank-icon.png" ); + break; + } + + case Preferences::PREF_CUSTOM_ICON: + { + pixmap.loadFromData( m_icon_data ); + break; + } + } + + QString number = QString::number( m_unread_mail ); + + if( m_unread_mail > 0 ) + { + /* + * Paint the number + */ + QPainter painter( &pixmap ); + + painter.setFont( QFont("Sans") ); + + double factor = pixmap.width() / ( 3 * painter.fontMetrics().width( number ) ); + QFont font = painter.font(); + font.setPointSizeF( font.pointSizeF() * factor ); + font.setBold( true ); + painter.setFont( font ); + + painter.drawText( pixmap.rect(), Qt::AlignCenter, QString::number( m_unread_mail ) ); + } + + /* + * Set the tray icon + */ + QSystemTrayIcon::setIcon( QIcon( pixmap ) ); +} + + +/* + * Handle unread mail signal + */ +void SysTrayXIcon::slotSetUnreadMail( int unread_mail ) +{ + setUnreadMail( unread_mail ); +} + + +/* + * Handle the icon type change signal + */ +void SysTrayXIcon::slotIconTypeChange() +{ + setIconType( m_pref->getIconType() ); +} + + +/* + * Handle the icon data change signal + */ +void SysTrayXIcon::slotIconDataChange() +{ + setIconMime( m_pref->getIconMime() ); + setIconData( m_pref->getIconData() ); +} diff --git a/app/SysTray-X/systrayxicon.h b/app/SysTray-X/systrayxicon.h new file mode 100644 index 0000000..478892a --- /dev/null +++ b/app/SysTray-X/systrayxicon.h @@ -0,0 +1,132 @@ +#ifndef SYSTRAYXICON_H +#define SYSTRAYXICON_H + +/* + * Local includes + */ +#include "preferences.h" + +/* + * Qt includes + */ +#include + +/* + * Predefines + */ +class SysTrayXLink; + + +/** + * @brief The systrayxtray class. The system tray icon. + */ +class SysTrayXIcon : public QSystemTrayIcon +{ + Q_OBJECT + + public: + + /** + * @brief SysTrayXIcon. Constructor. + * + * @param parent My parent. + */ + SysTrayXIcon( SysTrayXLink *link, Preferences *pref, QObject *parent = nullptr ); + + /** + * @brief setIconType. Set the sytem tray icon type. + * + * @param icon_type The icon type + */ + void setIconType( Preferences::IconType icon_type ); + + /** + * @brief setIconMime. Set the sytem tray icon mime. + * + * @param icon_mime The icon mime + */ + void setIconMime( const QString& icon_mime ); + + /** + * @brief setIconData. Set the custom icon data. + * + * @param icon_data The icon data. + */ + void setIconData( const QByteArray& icon_data ); + + /** + * @brief setUnreadMail. Set the number of unread mails. + * + * @param unread_mail The number of unread mails. + */ + void setUnreadMail( int unread_mail ); + + signals: + + /** + * @brief signalDebugMessage. Signal a debug message. + * + * @param message The message. + */ + void signalDebugMessage( QString message ); + + public slots: + + /** + * @brief slotSetUnreadMail. Slot for handling unread mail signals. + * + * @param unread_mail The number of unread mails. + */ + void slotSetUnreadMail( int unread_mail ); + + /** + * @brief slotIconTypeChange. Slot for handling icon type change signals. + */ + void slotIconTypeChange(); + + /** + * @brief slotIconDataChange. Slot for handling icon data change signals. + */ + void slotIconDataChange(); + + private: + + /** + * @brief setIcon. Set a new rendered icon. + */ + void renderIcon(); + + private: + + /** + * @brief m_link. Pointer to the link. + */ + SysTrayXLink *m_link; + + /** + * @brief m_pref Pointer to the preferences storage. + */ + Preferences *m_pref; + + /** + * @brief m_icon_type. Storage for the icon type. + */ + Preferences::IconType m_icon_type; + + /** + * @brief m_icon_mime. Storage for the icon mime. + */ + QString m_icon_mime; + + /** + * @brief m_icon_data. Storage for the icon. + */ + QByteArray m_icon_data; + + /** + * @brief m_unread_mail. Storage for the number of unread mails. + */ + int m_unread_mail; +}; + +#endif // SYSTRAYXICON_H diff --git a/app/SysTray-X/systrayxlink.cpp b/app/SysTray-X/systrayxlink.cpp index 098aaf5..07e2a31 100644 --- a/app/SysTray-X/systrayxlink.cpp +++ b/app/SysTray-X/systrayxlink.cpp @@ -3,52 +3,60 @@ /* * Local includes */ +#include "preferences.h" + +/* + * System includes + */ #include /* * Qt includes */ #include +#include +#include #include +#include +#include #include - /* * Constructor */ -SysTrayXLink::SysTrayXLink() +SysTrayXLink::SysTrayXLink( Preferences *pref ) { /* - * Open stdin + * Store preferences + */ + m_pref = pref; + + /* + * Open stdin */ m_stdin = new QFile( this ); m_stdin->open( stdin, QIODevice::ReadOnly ); /* - * Open stdout + * Open stdout */ m_stdout = new QFile( this ); m_stdout->open( stdout, QIODevice::WriteOnly ); /* - * Setup the notifiers + * Open dump.txt */ - m_notifierLinkRead = new QSocketNotifier( STDIN_FILENO, QSocketNotifier::Read, this ); - connect( m_notifierLinkRead, &QSocketNotifier::activated, this, &SysTrayXLink::slotLinkRead ); + m_dump = new QFile( "dump.txt", this ); + m_dump->open( QIODevice::WriteOnly ); - m_notifierLinkReadException = new QSocketNotifier( STDIN_FILENO, QSocketNotifier::Exception, this ); - connect( m_notifierLinkReadException, &QSocketNotifier::activated, this, &SysTrayXLink::slotLinkReadException ); - - - QDataStream out( m_stdout ); - - char reply[] = "\"Hallo other World!\""; - qint32 replylen = sizeof( reply ) - 1; - - - out.writeRawData( reinterpret_cast< char* >( &replylen ), sizeof( qint32 ) ); - out.writeRawData( reply, replylen ); + /* + * Setup the notifiers + */ + m_notifier_link_read = new QSocketNotifier( STDIN_FILENO, QSocketNotifier::Read, this ); + connect( m_notifier_link_read, &QSocketNotifier::activated, this, &SysTrayXLink::slotLinkRead ); + m_notifier_link_read_exception = new QSocketNotifier( STDIN_FILENO, QSocketNotifier::Exception, this ); + connect( m_notifier_link_read_exception, &QSocketNotifier::activated, this, &SysTrayXLink::slotLinkReadException ); } @@ -58,7 +66,7 @@ SysTrayXLink::SysTrayXLink() SysTrayXLink::~SysTrayXLink() { /* - * Cleanup + * Cleanup */ m_stdin->close(); delete m_stdin; @@ -66,66 +74,18 @@ SysTrayXLink::~SysTrayXLink() m_stdout->close(); delete m_stdout; - delete m_notifierLinkRead; - delete m_notifierLinkReadException; + m_dump->close(); + delete m_dump; + + delete m_notifier_link_read; + delete m_notifier_link_read_exception; } /* - * Read the input + * Write a message to the link */ -void SysTrayXLink::slotLinkRead() -{ - QDataStream in( m_stdin ); - - qint32 msglen; - int status1 = in.readRawData( reinterpret_cast< char* >( &msglen ), sizeof( qint32 ) ); - - emit signalReceivedMessageLength(msglen); - - QByteArray message(msglen + 1, 0 ); - int status2 = in.readRawData( message.data(), msglen ); - - emit signalReceivedMessage( message ); - - if( ( status1 == 4 ) && ( status2 == msglen ) ) - { - //dummy - } - -/* - QDataStream out( m_stdout ); - - char reply[] = "\"Hallo other World!\""; - qint32 replylen = sizeof( reply ) - 1; - - int status3 = out.writeRawData( reinterpret_cast< char* >( &replylen ), sizeof( qint32 ) ); - int status4 = out.writeRawData( reply, replylen ); - m_stdout->flush(); - - if( status3 && status4 ) - { - //dummy - } -*/ -} - - -/* - * Handle notifier exception - */ -void SysTrayXLink::slotLinkReadException() -{ - // Something went wrong -} - - - - -/* - * Read the input - */ -void SysTrayXLink::slotLinkWrite( QByteArray message ) +void SysTrayXLink::linkWrite( const QByteArray& message ) { QDataStream out( m_stdout ); @@ -135,8 +95,241 @@ void SysTrayXLink::slotLinkWrite( QByteArray message ) m_stdout->flush(); + if( status1 && status2 ) { -//dummy + //error handling? + } +} + + +/* + * Send the preferences to the add-on + */ +void SysTrayXLink::sendPreferences() +{ + /* + * Enacode the preferences into a JSON doc + */ + EncodePreferences( *m_pref ); + + + + QFile dump("/home/maxime/dumpJSON_app2addon.txt"); + dump.open(QIODevice::WriteOnly ); + dump.write( m_pref_json_doc.toJson( QJsonDocument::Compact ).data(), m_pref_json_doc.toJson( QJsonDocument::Compact ).length() ); + dump.close(); + + + + /* + * Send them to the add-on + */ + linkWrite( m_pref_json_doc.toJson( QJsonDocument::Compact ) ); +} + + +/* + * Decode JSON message + */ +void SysTrayXLink::DecodeMessage( const QByteArray& message ) +{ + QJsonParseError jsonError; + QJsonDocument jsonResponse = QJsonDocument::fromJson( message, &jsonError ); + + if( jsonError.error == QJsonParseError::NoError ) + { + QJsonObject jsonObject = jsonResponse.object(); + + if( jsonObject.contains( "unreadMail" ) && jsonObject[ "unreadMail" ].isDouble() ) + { + int unreadMail = jsonObject[ "unreadMail" ].toInt(); + emit signalUnreadMail( unreadMail ); + } + + if( jsonObject.contains( "preferences" ) && jsonObject[ "preferences" ].isObject() ) + { + + + QFile dump("/home/maxime/dumpJSON_addon2app.txt"); + dump.open(QIODevice::WriteOnly ); + dump.write( message.data(), message.length() ); + dump.close(); + + + + DecodePreferences( jsonObject[ "preferences" ].toObject() ); + } + } + else + { + emit signalLinkReceiveError( jsonError.errorString() ); + } +} + + +/* + * Decode preferences from JSON message + */ +void SysTrayXLink::DecodePreferences( const QJsonObject& pref ) +{ + /* + * Check the received object + */ + if( pref.contains( "iconType" ) && pref[ "iconType" ].isString() ) + { + Preferences::IconType icon_type = static_cast< Preferences::IconType >( pref[ "iconType" ].toString().toInt() ); + + /* + * Store the new icon type + */ + m_pref->setIconType( icon_type ); + } + + if( pref.contains( "iconMime" ) && pref[ "iconMime" ].isString() ) + { + QString icon_mime = pref[ "iconMime" ].toString(); + + /* + * Store the new icon mime + */ + m_pref->setIconMime( icon_mime ); + } + + if( pref.contains( "icon" ) && pref[ "icon" ].isString() ) + { + QString icon_base64 = pref[ "icon" ].toString(); + +/* + QFile dump("xxxxx"); + dump.open(QIODevice::WriteOnly ); + dump.write( icon_base64.toUtf8().data(), icon_base64.toUtf8().length() ); + dump.close(); +*/ + + /* + * Store the new icon data + */ + m_pref->setIconData( QByteArray::fromBase64( icon_base64.toUtf8() ) ); + } + + if( pref.contains( "debug" ) && pref[ "debug" ].isString() ) + { + bool debug = pref[ "debug" ].toString() == "true"; + + /* + * Store the new debug state + */ + m_pref->setDebug( debug ); + } +} + + +/* + * Encode preferences to JSON message + */ +void SysTrayXLink::EncodePreferences( const Preferences& pref ) +{ + /* + * Setup the preferences JSON + */ + QJsonObject prefObject; + prefObject.insert("debug", QJsonValue::fromVariant( QString( pref.getDebug() ? "true" : "false" ) ) ); + prefObject.insert("iconType", QJsonValue::fromVariant( QString::number( pref.getIconType() ) ) ); + prefObject.insert("iconMime", QJsonValue::fromVariant( pref.getIconMime() ) ); + prefObject.insert("icon", QJsonValue::fromVariant( QString( pref.getIconData().toBase64() ) ) ); + + QJsonObject preferencesObject; + preferencesObject.insert("preferences", prefObject ); + + /* + * Store the new document + */ + m_pref_json_doc = QJsonDocument( preferencesObject ); +} + + +/* + * Read the input + */ +void SysTrayXLink::slotLinkRead() +{ + QDataStream in( m_stdin ); + + qint32 msglen; + int status1 = in.readRawData( reinterpret_cast< char* >( &msglen ), sizeof( qint32 ) ); + + emit signalReceivedMessageLength( msglen ); + + QByteArray message(msglen, 0 ); + int status2 = in.readRawData( message.data(), msglen ); + + emit signalReceivedMessage( message ); + + m_dump->write( message ); + + /* + * Decode the message + */ + DecodeMessage( message ); + + + if( ( status1 == 4 ) && ( status2 == msglen ) ) + { + //error handling? + } +} + + +/* + * Handle read notifier exception + */ +void SysTrayXLink::slotLinkReadException() +{ + // Something went wrong +} + + +/* + * write the output + */ +void SysTrayXLink::slotLinkWrite( QByteArray message ) +{ + linkWrite( message ); +} + + + +/* + * Handle a debug state change signal + */ +void SysTrayXLink::slotDebugChange() +{ + if( m_pref->getAppPrefChanged() ) + { + sendPreferences(); + } +} + +/* + * Handle the icon type change signal + */ +void SysTrayXLink::slotIconTypeChange() +{ + if( m_pref->getAppPrefChanged() ) + { + sendPreferences(); + } +} + + +/* + * Handle the icon data change signal + */ +void SysTrayXLink::slotIconDataChange() +{ + if( m_pref->getAppPrefChanged() ) + { + sendPreferences(); } } diff --git a/app/SysTray-X/systrayxlink.h b/app/SysTray-X/systrayxlink.h index bca2efa..c4e8d7a 100644 --- a/app/SysTray-X/systrayxlink.h +++ b/app/SysTray-X/systrayxlink.h @@ -4,11 +4,13 @@ /* * Local includes */ +#include "preferences.h" /* * Qt includes */ #include +#include /* * Predefines @@ -28,27 +30,77 @@ class SysTrayXLink : public QObject /** * @brief SysTrayXLink. Constructor, destructor. */ - SysTrayXLink(); + SysTrayXLink( Preferences *pref ); ~SysTrayXLink(); + /** + * @brief linkWrite. Write a message to the link. + * + * @param message Message to be written. + */ + void linkWrite( const QByteArray& message ); + + /** + * @brief sendPreferences. Send the preferences to the add-on. + */ + void sendPreferences(); + + private: + + /** + * @brief MessageDecode. Decode a JSON message. + * + * @param message The message. + */ + void DecodeMessage( const QByteArray& message ); + + /** + * @brief DecodePreferences. Decode a JSON preference object. + * + * @param pref The JSON preferences. + */ + void DecodePreferences( const QJsonObject& pref ); + + /** + * @brief EncodePreferences. Encode the preferences into a JSON document. + * + * @param pref The preferences. + */ + void EncodePreferences( const Preferences& pref ); + public slots: + /** + * @brief slotDebugChange. Handle a change in debug state. + */ + void slotDebugChange(); + /** * @brief slotLinkWrite. Write the link. */ - void slotLinkWrite( QByteArray message ); + void slotLinkWrite( QByteArray message ); + + /** + * @brief slotIconTypeChange. Slot for handling icon type change signals. + */ + void slotIconTypeChange(); + + /** + * @brief slotIconDataChange. Slot for handling icon data change signals. + */ + void slotIconDataChange(); private slots: /** * @brief slotLinkRead. Read the link. */ - void slotLinkRead(); + void slotLinkRead(); /** * @brief slotLinkReadException. Handle a read link exception. */ - void slotLinkReadException(); + void slotLinkReadException(); signals: @@ -57,17 +109,43 @@ class SysTrayXLink : public QObject * * @param msglen */ - void signalReceivedMessageLength(qint32 msglen); + void signalReceivedMessageLength( qint32 msglen ); /** * @brief signalReceivedMessage * * @param message */ - void signalReceivedMessage(QByteArray message); + void signalReceivedMessage( QByteArray message ); + + /** + * @brief signalLinkReceiveError. Cannot parse received JSON message. + * + * @param error JSON error message + */ + void signalLinkReceiveError( QString error ); + + /** + * @brief signalDebugMessage. Signal a debug message. + * + * @param message The message. + */ + void signalDebugMessage( QString message ); + + /** + * @brief signalUnreadMail. Signal numder of unread mails. + * + * @param unreadMail The number of unread mails. + */ + void signalUnreadMail( int unread_mail ); private: + /** + * @brief m_pref. Pointer to the preferences storage. + */ + Preferences *m_pref; + /** * @brief m_stdin. Pointer to stdin file. */ @@ -79,14 +157,24 @@ class SysTrayXLink : public QObject QFile *m_stdout; /** - * @brief m_notifierLinkRead. Pointers to the link read data notifier. + * @brief m_dump. Pointer to dump file. */ - QSocketNotifier *m_notifierLinkRead; + QFile *m_dump; /** - * @brief m_notifierLinkReadException. Pointers to the link read exception notifier. + * @brief m_notifier_link_read. Pointers to the link read data notifier. */ - QSocketNotifier *m_notifierLinkReadException; + QSocketNotifier *m_notifier_link_read; + + /** + * @brief m_notifier_link_read_exception. Pointers to the link read exception notifier. + */ + QSocketNotifier *m_notifier_link_read_exception; + + /** + * @brief m_pref_json_doc. Temporary storage for the preferences to be send. + */ + QJsonDocument m_pref_json_doc; }; #endif // SYSTRAYXLINK_H diff --git a/webext/background.js b/webext/background.js index 4e7854e..6959fce 100644 --- a/webext/background.js +++ b/webext/background.js @@ -13,26 +13,62 @@ SysTrayX.Messaging = { ], init: function() { - if (this.initialized) { - console.log("Messaging already initialized"); - return; - } console.log("Enabling Messaging"); + // Get the accounts from the storage + SysTrayX.Messaging.getAccounts(); + browser.storage.onChanged.addListener(SysTrayX.Messaging.storageChanged); + + // Send preferences to app + SysTrayX.Messaging.sendPreferences(); + // this.unReadMessages(this.unreadFiltersTest).then(this.unreadCb); - window.setInterval(SysTrayX.Messaging.pollAccounts, 1000); + window.setInterval(SysTrayX.Messaging.pollAccounts, 10000); this.initialized = true; }, + // + // Handle a storage change + // + storageChanged: function(changes, area) { + console.debug("Changes in store"); + + // Get the new preferences + SysTrayX.Messaging.getAccounts(); + + if ("addonprefchanged" in changes && changes["addonprefchanged"].newValue) { + console.debug("Sending preference"); + + // + // Send new preferences to the app + // + SysTrayX.Messaging.sendPreferences(); + + // Reset flag + browser.storage.sync.set({ + addonprefchanged: false + }); + } + + /* + var changedItems = Object.keys(changes); + for (var item of changedItems) { + console.log(item + " has changed:"); + console.log("Old value: "); + console.log(changes[item].oldValue); + console.log("New value: "); + console.log(changes[item].newValue); + } +*/ + }, + // // Poll the accounts // pollAccounts: function() { console.debug("Polling"); - SysTrayX.Messaging.getAccounts(); - // // Get the unread nessages of the selected accounts // @@ -40,14 +76,16 @@ SysTrayX.Messaging = { let filtersAttr = filtersDiv.getAttribute("data-filters"); let filters = JSON.parse(filtersAttr); - SysTrayX.Messaging.unReadMessages(filters).then( - SysTrayX.Messaging.unreadCb - ); + if (filters.length > 0) { + SysTrayX.Messaging.unReadMessages(filters).then( + SysTrayX.Messaging.unreadCb + ); + } }, // - // Use the messages API to get the unread messages (Promise) - // Be aware that the data is only avaiable inside the callback + // Use the messages API to get the unread messages (Promise) + // Be aware that the data is only avaiable inside the callback // unReadMessages: async function(filters) { let unreadMessages = 0; @@ -68,36 +106,55 @@ SysTrayX.Messaging = { }, // - // Callback for unReadMessages + // Callback for unReadMessages // unreadCb: function(count) { - console.log("SysTrayX unread " + count); + SysTrayX.Link.postSysTrayXMessage({ unreadMail: count }); + }, + + sendPreferences: function() { + console.debug("Send preferences"); + + let getter = browser.storage.sync.get([ + "debug", + "iconType", + "iconMime", + "icon" + ]); + getter.then(this.sendPreferencesStorage, this.onSendPreferecesStorageError); + }, + + sendPreferencesStorage: function(result) { + console.debug("Get preferences from storage"); + + let debug = result.debug || "false"; + let iconType = result.iconType || "0"; + let iconMime = result.iconMime || "image/png"; + let icon = result.icon || []; + + console.log("Debug" + debug); + console.log("Type" + iconType); + console.log("Mime" + iconMime); + console.log(icon); + + // Send it to the app + SysTrayX.Link.postSysTrayXMessage({ + preferences: { + debug: debug, + iconType: iconType, + iconMime: iconMime, + icon: icon + } + }); + }, + + onSendIconStorageError: function(error) { + console.log(`GetIcon Error: ${error}`); }, // - // Get the accounts from the storage and - // make them available in the background HTML + // Get the accounts from the storage // - getAccountsStorage: function(result) { - console.debug("Get accounts from storage"); - - let accounts = result.accounts || []; - - // Store them in the background HTML - let accountsDiv = document.getElementById("accounts"); - accountsDiv.setAttribute("data-accounts", JSON.stringify(accounts)); - - let filters = result.filters || []; - - // Store them in the background HTML - let filtersDiv = document.getElementById("filters"); - filtersDiv.setAttribute("data-filters", JSON.stringify(filters)); - }, - - onGetAccountsStorageError: function(error) { - console.log(`GetAccounts Error: ${error}`); - }, - getAccounts: function() { console.debug("Get accounts"); @@ -113,42 +170,98 @@ SysTrayX.Messaging = { let accounts = JSON.parse(accountsAttr); console.debug("Accounts poll: " + accounts.length); } + }, + + // + // Get the accounts from the storage and + // make them available in the background HTML + // + getAccountsStorage: function(result) { + console.debug("Get accounts from storage"); + + let accounts = result.accounts || []; + + // Store them in the background HTML + let accountsDiv = document.getElementById("accounts"); + accountsDiv.setAttribute("data-accounts", JSON.stringify(accounts)); + + let filters = result.filters || []; + + // Store them in the background HTML + let filtersDiv = document.getElementById("filters"); + filtersDiv.setAttribute("data-filters", JSON.stringify(filters)); + }, + + onGetAccountsStorageError: function(error) { + console.log(`GetAccounts Error: ${error}`); } }; // -// Link object, handles the native messaging to the system tray app +// Link object. Handles the native messaging to the system tray app // SysTrayX.Link = { portSysTrayX: undefined, init: function() { - // Connect to the app + // Connect to the app this.portSysTrayX = browser.runtime.connectNative("SysTray_X"); // Listen for messages from the app. this.portSysTrayX.onMessage.addListener( SysTrayX.Link.receiveSysTrayXMessage ); - - // Setup test loop - window.setInterval(SysTrayX.Link.postSysTrayXMessage, 1000); }, - postSysTrayXMessage: function() { - console.log("Sending: Hallo World!"); - SysTrayX.Link.portSysTrayX.postMessage("Hallo World!"); - // SysTrayX.Link.portSysTrayX.postMessage({ key: "Hallo", value: "World!" }); + postSysTrayXMessage: function(object) { + // Send object (will be stringified by postMessage) + SysTrayX.Link.portSysTrayX.postMessage(object); }, receiveSysTrayXMessage: function(response) { console.log("Received: " + response); + + if (response["preferences"]) { + // Store the preferences from the app + console.log("Preferences received"); + + let iconMime = response["preferences"].iconMime; + if (iconMime) { + browser.storage.sync.set({ + iconMime: iconMime + }); + } + + let icon = response["preferences"].icon; + if (icon) { + browser.storage.sync.set({ + icon: icon + }); + } + + let iconType = response["preferences"].iconType; + if (iconType) { + browser.storage.sync.set({ + iconType: iconType + }); + } + + let debug = response["preferences"].debug; + if (debug) { + browser.storage.sync.set({ + debug: debug + }); + } + } } }; console.log("Starting SysTray-X"); -SysTrayX.Messaging.init(); +// Setup the link first SysTrayX.Link.init(); +// Main start +SysTrayX.Messaging.init(); + console.log("Done"); diff --git a/webext/css/options.css b/webext/css/options.css index 6d90408..87f6ebb 100644 --- a/webext/css/options.css +++ b/webext/css/options.css @@ -100,3 +100,11 @@ ul, .active { display: block; } + +.custom-icon-container { + display: flex; +} + +.custom-icon-container > div { + margin: 10px; +} diff --git a/webext/js/options_accounts.js b/webext/js/options_accounts.js index 75d592a..f256749 100644 --- a/webext/js/options_accounts.js +++ b/webext/js/options_accounts.js @@ -4,15 +4,7 @@ SysTrayX.Accounts = { initialized: false, init: function() { - if (this.initialized) { - console.log("Accounts already initialized"); - return; - } - console.log("Enabling Accounts"); - this.getAccounts().then(this.getAccountsCb); - - this.initialized = true; }, /* diff --git a/webext/js/options_iconform.js b/webext/js/options_iconform.js new file mode 100644 index 0000000..eca3786 --- /dev/null +++ b/webext/js/options_iconform.js @@ -0,0 +1,36 @@ +function fileSelected() { + let input = document.getElementById("selectedFileIconType"); + + if (input.files.length > 0) { + console.debug("Selected file: " + input.files[0].name); + console.debug("Selected file type: " + input.files[0].type); + } + + function storeFile() { + let buffer = new Uint8Array(fr.result); + + let binary = ""; + let len = buffer.byteLength; + for (let i = 0; i < len; i++) { + binary += String.fromCharCode(buffer[i]); + } + + let base64 = window.btoa(binary); + let iconDiv = document.getElementById("icon"); + iconDiv.setAttribute("data-icon", base64); + iconDiv.setAttribute("data-icon-mime", input.files[0].type); + + let image = document.getElementById("customIconImage"); + image.setAttribute("src", `data:${input.files[0].type};base64,${base64}` ); + + console.log(base64); + } + + fr = new FileReader(); + fr.onload = storeFile; + fr.readAsArrayBuffer(input.files[0]); +} + +document + .getElementById("selectedFileIconType") + .addEventListener("change", fileSelected); diff --git a/webext/options.html b/webext/options.html index cae3755..775b2f9 100644 --- a/webext/options.html +++ b/webext/options.html @@ -9,7 +9,13 @@ - + + + + Display debug window + + + __MSG_tabWindows__ __MSG_tabIcon__ @@ -21,7 +27,7 @@ Windows Windows options here - Please select your opton: + Please select your option: Option 1 Option 2 Option 3 @@ -30,22 +36,46 @@ Check 1 Check 2 Check 3 + - + Icon - Icon options here. + + Please select your option: + + + + Blank icon + + + New mail icon + + + Custom icon + + + Browse... + + + + + + + + + - + Included accounts - + diff --git a/webext/options.js b/webext/options.js index f5744f7..c5cf65b 100644 --- a/webext/options.js +++ b/webext/options.js @@ -1,94 +1,302 @@ -function saveOptions(e) { - e.preventDefault(); +var SysTrayX = {}; - console.debug("Save preferences"); +SysTrayX.SaveOptions = { + start: function(e) { + e.preventDefault(); - browser.storage.sync.set({ - optionsRadioTest: document.querySelector( - 'input[name="options_test"]:checked' - ).value, - optionsCheck1: document.querySelector('input[name="check1"]').checked, - optionsCheck2: document.querySelector('input[name="check2"]').checked, - optionsCheck3: document.querySelector('input[name="check3"]').checked - }); + console.debug("Save preferences"); - /* - * Save accounts and filters - */ + browser.storage.sync.set({ + optionsRadioTest: document.querySelector( + 'input[name="options_test"]:checked' + ).value, + optionsCheck1: document.querySelector('input[name="check1"]').checked, + optionsCheck2: document.querySelector('input[name="check2"]').checked, + optionsCheck3: document.querySelector('input[name="check3"]').checked + }); - console.debug("Store accounts and filters"); + // + // Save accounts and filters + // - let treeBase = document.getElementById("accountsTree"); - let inputs = treeBase.querySelectorAll("input"); - let accounts = []; - let filters = []; - for (let i = 0; i < inputs.length; ++i) { - let account = JSON.parse(inputs[i].value); - let checked = inputs[i].checked; - accounts.push({ ...account, checked: checked }); + console.debug("Store accounts and filters"); - if (checked) { - let inboxMailFolder = account.folders.find(obj => obj.type === "inbox"); + let treeBase = document.getElementById("accountsTree"); + let inputs = treeBase.querySelectorAll("input"); + let accounts = []; + let filters = []; + for (let i = 0; i < inputs.length; ++i) { + let account = JSON.parse(inputs[i].value); + let checked = inputs[i].checked; + accounts.push({ ...account, checked: checked }); - if (inboxMailFolder) { - console.debug("Filter Id: " + inboxMailFolder.accountId); - console.debug("Filter Path: " + inboxMailFolder.path); + if (checked) { + let inboxMailFolder = account.folders.find(obj => obj.type === "inbox"); - filters.push({ - unread: true, - folder: inboxMailFolder - }); + if (inboxMailFolder) { + console.debug("Filter Id: " + inboxMailFolder.accountId); + console.debug("Filter Path: " + inboxMailFolder.path); + + filters.push({ + unread: true, + folder: inboxMailFolder + }); + } } } + + // Store accounts + browser.storage.sync.set({ + accounts: accounts + }); + + // Store query filters + browser.storage.sync.set({ + filters: filters + }); + + console.debug("Store accounts and filters done"); + + // + // Save debug state + // + let debug = document.querySelector('input[name="debug"]').checked; + browser.storage.sync.set({ + debug: `${debug}` + }); + console.debug("Store debug state: " + `${debug}`); + + // + // Save icon preferences + // + + console.debug("Store icon preferences"); + + let iconType = document.querySelector('input[name="iconType"]:checked') + .value; + + // Store icon type + browser.storage.sync.set({ + iconType: iconType + }); + + let iconDiv = document.getElementById("icon"); + let iconBase64 = iconDiv.getAttribute("data-icon"); + let iconMime = iconDiv.getAttribute("data-icon-mime"); + + // Store icon (base64) + browser.storage.sync.set({ + iconMime: iconMime, + icon: iconBase64 + }); + + console.debug("Store icon preferences done"); + + // Mark add-on preferences changed + browser.storage.sync.set({ + addonprefchanged: true + }); } +}; - // Store accounts - browser.storage.sync.set({ - accounts: accounts - }); +SysTrayX.RestoreOptions = { + start: function() { + console.debug("Restore preferences"); - // Store query filters - browser.storage.sync.set({ - filters: filters - }); + // + // Test 1 + // + let getting = browser.storage.sync.get("optionsRadioTest"); + getting.then( + SysTrayX.RestoreOptions.setCurrentRadioChoice, + SysTrayX.RestoreOptions.onError + ); - console.debug("Store accounts and filters done"); -} + // + // Test 2 + // + getting = browser.storage.sync.get([ + "optionsCheck1", + "optionsCheck2", + "optionsCheck3" + ]); + getting.then( + SysTrayX.RestoreOptions.setCurrentCheckChoice, + SysTrayX.RestoreOptions.onError + ); -function restoreOptions() { - console.debug("Restore preferences"); + console.debug("Restore icon preferences"); - function setCurrentRadioChoice(result) { + // + // Restore debug state + // + let getDebug = browser.storage.sync.get("debug"); + getDebug.then( + SysTrayX.RestoreOptions.setDebug, + SysTrayX.RestoreOptions.onDebugError + ); + + // + // Restore icon type + // + let getIconType = browser.storage.sync.get("iconType"); + getIconType.then( + SysTrayX.RestoreOptions.setIconType, + SysTrayX.RestoreOptions.onIconTypeError + ); + + // + // Restore icon + // + let getIcon = browser.storage.sync.get(["iconMime", "icon"]); + getIcon.then( + SysTrayX.RestoreOptions.setIcon, + SysTrayX.RestoreOptions.onIconError + ); + + console.debug("Restore icon preferences done"); + }, + + // + // Test 1 Callback + // + setCurrentRadioChoice: function(result) { let selector = result.optionsRadioTest || "Option1"; let radioButton = document.querySelector(`[value=${selector}]`); radioButton.checked = true; - } + }, - function setCurrentCheckChoice(result) { + // + // Test 2 Callback + // + setCurrentCheckChoice: function(result) { let checkbox1 = document.querySelector('[name="check1"]'); checkbox1.checked = result.optionsCheck1 || false; let checkbox2 = document.querySelector('[name="check2"]'); checkbox2.checked = result.optionsCheck2 || false; let checkbox3 = document.querySelector('[name="check3"]'); checkbox3.checked = result.optionsCheck3 || false; - } + }, - function onError(error) { + // + // Test 1+2 error callback + // + onError: function(error) { console.log(`Error: ${error}`); + }, + + // + // Restore debug state callbacks + // + setDebug: function(result) { + let debug = result.debug || "false"; + + console.debug("Debug: " + debug); + + let checkbox = document.querySelector(`input[name="debug"]`); + checkbox.checked = (debug === "true"); + }, + + onDebugError: function(error) { + console.log(`Debug Error: ${error}`); + }, + + // + // Restore icon type callbacks + // + setIconType: function(result) { + let iconType = result.iconType || "0"; + let radioButton = document.querySelector(`[value="${iconType}"]`); + radioButton.checked = true; + }, + + onIconTypeError: function(error) { + console.log(`Icon type Error: ${error}`); + }, + + // + // Restore icon + // + setIconMime: function(result) { + let iconMime = result.iconMime || "image/png"; + + let iconDiv = document.getElementById("icon"); + iconDiv.setAttribute("data-icon-mime", iconMime); + }, + + setIconData: function(result) { + let iconBase64 = result.icon || ""; + + let iconDiv = document.getElementById("icon"); + iconDiv.setAttribute("data-icon", iconBase64); + }, + + updateIconImage: function() { + let iconDiv = document.getElementById("icon"); + icon_mime = iconDiv.getAttribute("data-icon-mime"); + icon_data = iconDiv.getAttribute("data-icon"); + + let image = document.getElementById("customIconImage"); + image.setAttribute("src", `data:${icon_mime};base64,${icon_data}`); + }, + + setIcon: function(result) { + SysTrayX.RestoreOptions.setIconMime(result); + SysTrayX.RestoreOptions.setIconData(result); + + SysTrayX.RestoreOptions.updateIconImage(); + }, + + onIconError: function(error) { + console.log(`Icon Error: ${error}`); } +}; - var getting = browser.storage.sync.get("optionsRadioTest"); - getting.then(setCurrentRadioChoice, onError); +SysTrayX.StorageChanged = { + changed: function(changes, area) { + // Try to keep the preferences of the add-on and the app in sync + let changedItems = Object.keys(changes); - var getting = browser.storage.sync.get([ - "optionsCheck1", - "optionsCheck2", - "optionsCheck3" - ]); - getting.then(setCurrentCheckChoice, onError); -} + let changed_icon = false; + let changed_icon_mime = false; + for (let item of changedItems) { + if (item === "iconMime") { + SysTrayX.RestoreOptions.setIconMime({ + iconMime: changes[item].newValue + }); + } + if (item === "icon") { + SysTrayX.RestoreOptions.setIcon({ icon: changes[item].newValue }); + changed_icon = true; + } + if (item === "iconType") { + SysTrayX.RestoreOptions.setIconType({ + iconType: changes[item].newValue + }); + changed_icon_mime = true; + } + if (item === "debug") { + SysTrayX.RestoreOptions.setDebug({ + debug: changes[item].newValue + }); + } + } -document.addEventListener("DOMContentLoaded", restoreOptions); + if (changed_icon_mime && changed_icon) { + SysTrayX.RestoreOptions.updateIconImage(); + } + + // + // Update element + // + document.getElementById("debugselect").className = "active"; + document.getElementById("iconselect").className = "active"; + } +}; + +document.addEventListener("DOMContentLoaded", SysTrayX.RestoreOptions.start); document .querySelector('[name="saveform"]') - .addEventListener("submit", saveOptions); + .addEventListener("submit", SysTrayX.SaveOptions.start); + +browser.storage.onChanged.addListener(SysTrayX.StorageChanged.changed);
Windows options here
Please select your opton:
Please select your option:
Icon options here.