Еще один гайд по созданию плазмоида: конфигурация, события и уведомления

от автора


Dr.Konqi, мы с ним дружим, я его часто вижу %)

Вместо предисловия

Привет!
На хабре уже писали про то, что все плазмоиды нужно портировать на QML/JS, но я все равно продолжаю измываться над трупом CPP и пишу виджеты для плазмы на плюсах. Но, возможно, не все так плохо, %username%?

Для более простого примера написания плазмоида на C++ можно обратиться к этой статье. В настоящей же статье на голый виджет мы попробуем добавить немного фич (в порядке возрастания) — конфигурационный интерфейс, обработку некоторых событий и уведомления.
Если кого заинтересовало — продолжение ниже.

Идея виджета

Так как задачка для меня была исключительно учебно-самообразовательной, то идея виджета проста: возьмем и форкнем виджет Oblique Strategies для GNOME. Таким образом, в нашем виджете будет:

  • Label с текстом с карточек
  • Label с копирайтом (служит в первую очередь для указания текущей редакции)
  • Конфигурационный интерфейс, включающий в себя настройку текста и выбор редакции
  • Обновление текста по клику мышкой
  • Опциональная функция автообновления
  • Опциональная функция вывода текущего сообщения при автоматической смене в стандартные уведомления

Компоненты

Виджет

Хидер

#ifndef OBLIKUESTRATEGIES_H #define OBLIKUESTRATEGIES_H  #include <Plasma/Applet> #include <Plasma/Label>  #include <ui_configwindow.h>  class QGraphicsLinearLayout;  class oblikuestrategies : public Plasma::Applet {   Q_OBJECT public:   oblikuestrategies(QObject *parent, const QVariantList &args);   ~oblikuestrategies();   int setMessagesText();   void init();  public slots:   int autoUpdateEvent();   int sendNotification(QString eventId, int num);   int updateEvent();   void mousePressEvent(QGraphicsSceneMouseEvent *event);   // for configuration interface   int setAutoUpdate();   void configAccepted();   void configChanged();  protected:   void createConfigurationInterface(KConfigDialog *parent);  private:   // ui   Plasma::Label *main_label;   Plasma::Label *info_label;   QTimer *timer;   // variables   bool autoUpdate_bool, notify_bool;   int autoUpdate_int, edition, fontSize, fontWeight;   QString fontFamily, fontColor, fontStyle;   QStringList formatLine, copyright;   QList<QStringList> mess;   // configuration interface   Ui::ConfigWindow uiConfig; };  K_EXPORT_PLASMA_APPLET(oblikue-strategies, oblikuestrategies) #endif /* OBLIKUESTRATEGIES_H */

Это будет эдакая «карта». Суть K_EXPORT_PLASMA_APPLET рассказана в указанной выше статье (это единственная принципиально важная штука в хидере). Подключим первоначальные библиотеки, объявим класс и деструктор

#include "oblikue-strategies.h" #include <QGraphicsLinearLayout> #include <plasma/theme.h>  oblikuestrategies::oblikuestrategies(QObject *parent, const QVariantList &args) :   Plasma::Applet(parent, args) {   setBackgroundHints(DefaultBackground);   setHasConfigurationInterface(true); }  oblikuestrategies::~oblikuestrategies() {   delete info_label;   delete main_label;   delete timer; }

ничего особо интересно. Замечу только, что мы тут установили, что у апплета есть конфигурационный интерфейс. Суть переменных будет ясна чуть ниже. Далее соберем функцию инициализации:

void oblikuestrategies::init() {   if (setMessagesText() != 0)     return;    // generate ui   // layout   QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);   layout->setOrientation(Qt::Vertical);   // label   layout->addStretch(1);   main_label = new Plasma::Label(this);   main_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);   main_label->setToolTip(qApp->translate("tooltip", "Click here to update message"));   layout->addItem(main_label);   layout->addStretch(1);   // copyright label   info_label = new Plasma::Label(this);   layout->addItem(info_label); }

Функция int setMessagesText() забивает переменные copyright и собственно текст карт (mess), попутно создает список из двух элементов formatLine. Затем мы создаем Layout, на ней две метки — одна для текста, другая для копирайта — и кидаем распорки (stretch) для красивого вида. Далее перейдем к конфигурационному интерфейсу

Конфигурация

Нарисуем формочку. Пусть она будет такой:

Теперь прикрутим функции. Считывание конфига:

void oblikuestrategies::configChanged() {   KConfigGroup cg = config();    edition = cg.readEntry("edition", 1);   fontFamily = cg.readEntry("font_family", "Terminus"); ... }

Обращу ваше внимание на то, как считываются переменные. Метод readEntry имеет два аргумента — первый имя переменной в конфигурационном файле (в глубине хомяка plasma-desktop-appletrc), второй — дефолтное значение. Настройки, записанные с помощью KConfigGroup, будут сохранены в указанном выше файле. Добавлю, что эта функция автоматически вызовется, если были изменены настройки виджета.
Не забыли про запись конфига:

void oblikuestrategies::configAccepted() {   KConfigGroup cg = config();    cg.writeEntry("edition", uiConfig.comboBox_edition->currentIndex()+1);   cg.writeEntry("font_family", uiConfig.fontComboBox_font->currentFont().family()); ... }

Аналогично считыванию. Метод writeEntry также имеет 2 аргумента — имя и то, откуда брать значения. Теперь сам интерфейс прикрутим:

void oblikuestrategies::createConfigurationInterface(KConfigDialog *parent) {   QWidget *configwin = new QWidget;   uiConfig.setupUi(configwin);    uiConfig.comboBox_edition->setCurrentIndex(edition-1); ...   parent->addPage(configwin, i18n("Oblikue Strategies"), Applet::icon());   connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); }

Объявили интерфейс, выставили значения (переменные уже считаны в init() вызовом метода configChanged()). Потом добавили интерфейс к окошечку (метод addPage — первый аргумент что, второй как назвать и третий иконка). И связали кнопку с сохранением настроек. Дальше прикрутим эвенты.

Обработка событий

Пусть у нас есть некоторый метод, который отвечает за обновление текста. Назовем его int updateEvent() (возвращает номер вызванного сообщения). Прикрутим обработку клика мыши:

void oblikuestrategies::mousePressEvent(QGraphicsSceneMouseEvent *event) {   // mouse click event   if (event->buttons() == Qt::LeftButton)     updateEvent(); }

Если двойной клик, то нужно наследоваться от mouseDoubleClickEvent и, очевидно, проверка на кнопку не нужна. Теперь добавим автообновление. Сначала добавим в метод init() объявление таймера:

... // timer   timer = new QTimer(this);   timer->setSingleShot(false); ...

Установим его в «многоразовое» использование (setSingleShot(false)). Далее прикрутим отключение и включение таймера в методе configChanged():

  if (autoUpdate_bool == true)   {     disconnect(timer, SIGNAL(timeout()), this, SLOT(autoUpdateEvent()));     timer->stop();   } // считывание переменных ...   if (autoUpdate_bool == true)   {     connect(timer, SIGNAL(timeout()), this, SLOT(autoUpdateEvent()));     timer->start(autoUpdate_int * MSEC_IN_MIN);   }

На всякий случай: метод start() имеет аргумент период в мсек. Добавим функцию автообновления:

int oblikuestrategies::autoUpdateEvent() {   // auto update text   int num = updateEvent();   if (notify_bool == true)     if (sendNotification(QString("newMessage"), num) != 0)       return 1;   return 0; }

Тут то нам и понадобилось значение, возвращаемое методом updateEvent(). Данный метод вызывает обновление текста, затем, если установлено notify_bool == true вызывает метод, который отправляет уведомления в KDE.

Уведомления

Сначала создадим файлик plasma_applet_oblikue-strategies.notifyrc

[Global] IconName=oblikue-strategies Name=Oblikue Strategies Comment=Oblikue Strategies  [Event/newMessage] Name=New message Comment=There is auto updated message in widget Action=Popup 

Первое — общие настройки, их можно оставить без комментариев. Дальше идет перечисление событий и что они из себя представляют. Теперь вернемся к исходникам. Один единственный метод:

int oblikuestrategies::sendNotification(QString eventId, int num) {   // send notification   KNotification *notification = new KNotification(eventId);   notification->setComponentData(KComponentData("plasma_applet_oblikue-strategies"));   notification->setTitle(QString(i18n("Oblikue Strategies")));   notification->setText(mess[edition-1][num]);   notification->sendEvent();   delete notification;   return 0; }

eventId — собственно наш эвент. В методе setComponentData указываем имя апплета (чтоб не путаться и для упрощения). Ставим подпись, текст и отправляем сообщение в систему.

Сборка

ls -1 sources

CMakeLists.txt configwindow.ui oblikue-strategies.cpp oblikue-strategies.h oblikue-strategies.png plasma-applet-oblikue-strategies.desktop plasma_applet_oblikue-strategies.notifyrc 

CMakeLists.txt

project (plasma_applet_oblikue-strategies)  find_package (KDE4 REQUIRED) include (KDE4Defaults)  add_definitions (${QT_DEFINITIONS}                   ${KDE4_DEFINITIONS}) include_directories (${CMAKE_SOURCE_DIR}                       ${CMAKE_BINARY_DIR}                       ${KDE4_INCLUDES})  set (PLUGIN_NAME ${PROJECT_NAME}) file (GLOB PROJECT_DESKTOP *.desktop) file (GLOB PROJECT_ICON *.png) file (GLOB PROJECT_NOTIFY *.notifyrc) file (GLOB PROJECT_SOURCE *.cpp) file (GLOB PROJECT_UI *.ui)  kde4_add_ui_files (PROJECT_SOURCE ${PROJECT_UI}) kde4_add_plugin (${PLUGIN_NAME} ${PROJECT_SOURCE}) target_link_libraries (${PLUGIN_NAME} ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS})  # install install (TARGETS ${PLUGIN_NAME} DESTINATION ${PLUGIN_INSTALL_DIR}) install (FILES ${PROJECT_DESKTOP} DESTINATION ${SERVICES_INSTALL_DIR}) install (FILES ${PROJECT_ICON} DESTINATION ${ICON_INSTALL_DIR}) install (FILES ${PROJECT_NOTIFY} DESTINATION ${DATA_INSTALL_DIR}/${PLUGIN_NAME}) 

Файлик не совсем правильный (с точки зрения человеческого фактора, например), но универсальный (поменять только имя проекта на нужное). Из отличий от обычных файлов сборок — вызов kde4_add_ui_files для создания конфигурационного интерфейса. И установка файла с нотификациями.

Постскриптум

Исходники этого безобразия.
Что получилось:

По материалам

Спасибо за внимание!

ссылка на оригинал статьи http://habrahabr.ru/post/192698/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *