http://wiki.linuxformat.ru/wiki/index.php?title=LXF110:KDE4&feed=atom&action=historyLXF110:KDE4 - История изменений2024-03-29T13:28:28ZИстория изменений этой страницы в викиMediaWiki 1.19.20+dfsg-0+deb7u3http://wiki.linuxformat.ru/wiki/index.php?title=LXF110:KDE4&diff=8808&oldid=prevYaleks в 10:55, 4 октября 20092009-10-04T10:55:41Z<p></p>
<table class='diff diff-contentalign-left'>
<col class='diff-marker' />
<col class='diff-content' />
<col class='diff-marker' />
<col class='diff-content' />
<tr valign='top'>
<td colspan='2' style="background-color: white; color:black;">← Предыдущая</td>
<td colspan='2' style="background-color: white; color:black;">Версия 10:55, 4 октября 2009</td>
</tr><tr><td colspan="2" class="diff-lineno">Строка 12:</td>
<td colspan="2" class="diff-lineno">Строка 12:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>4.1.x, стабилизируются надолго.</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>4.1.x, стабилизируются надолго.</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">{{Врезка</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">|Заголовок=Скорая помощь</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">|Содержание=Файл /proc/meminfo, как</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">и все в директории /proc,</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">является</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">виртуальным.</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">Он не хранится</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">на диске,</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">а формируется</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">системой</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">в ответ на наши</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">запросы. Когда</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">мы читаем этот</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">файл, мы получаем данные</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">о состоянии</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">памяти</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">на момент</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">чтения.</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">|Ширина=150px}}</ins></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Как отмечалось в предыдущей статье, информационные расширения Plasma используются в основном для отображения данных, меняющихся во времени – нагрузки на систему, сетевого трафика, прогнозов погоды и т.п. (хотя ничто не мешает использовать плазмоиды и</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Как отмечалось в предыдущей статье, информационные расширения Plasma используются в основном для отображения данных, меняющихся во времени – нагрузки на систему, сетевого трафика, прогнозов погоды и т.п. (хотя ничто не мешает использовать плазмоиды и</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>для отображения статических данных, вряд ли пользователи захотят</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>для отображения статических данных, вряд ли пользователи захотят</div></td></tr>
<tr><td colspan="2" class="diff-lineno">Строка 190:</td>
<td colspan="2" class="diff-lineno">Строка 209:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>/share/kde4/services/. Если эти значения устраивают вашу систему,</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>/share/kde4/services/. Если эти значения устраивают вашу систему,</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>то все в порядке (для проверки выясните, существует ли в вашей</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>то все в порядке (для проверки выясните, существует ли в вашей</div></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div>системе директория /share/kde4/services/ и хранит ли она уже установленные .desktop-файлы). В моей системе KDE ищет файлы расширений в директориях с теми же именами, что заданы по умолчанию,</div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div>системе директория /share/kde4/services/ и хранит ли она уже установленные .desktop-файлы). В моей системе KDE ищет файлы расширений в директориях с теми же именами, что заданы по умолчанию, но расположенных в /usr, поэтому в самом начале я меняю значение</div></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div>но расположенных в /usr, поэтому в самом начале я меняю значение</div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>переменной CMAKE_INSTALL_PREFIX.</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>переменной CMAKE_INSTALL_PREFIX.</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">[[Изображение:LXF110 86 1.png|200px|thumb|Рис. 1. Утилита Plasma Engine Explorer.]]</ins></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Прежде чем писать для нашего поставщика данных апплет Plasma,</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Прежде чем писать для нашего поставщика данных апплет Plasma,</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>желательно убедиться, что он работает корректно (иначе мы не</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>желательно убедиться, что он работает корректно (иначе мы не</div></td></tr>
<tr><td colspan="2" class="diff-lineno">Строка 256:</td>
<td colspan="2" class="diff-lineno">Строка 275:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>В первом аргументе слоту dataUpdated() передается имя источника обновляемых данных, во втором – ссылка на объект</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>В первом аргументе слоту dataUpdated() передается имя источника обновляемых данных, во втором – ссылка на объект</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Plasma::DataEngine::Data, который содержит сами данные. Схему взаимодействия между плазмоидом и поставщиком данных можно отобразить графически (рис. 2).</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Plasma::DataEngine::Data, который содержит сами данные. Схему взаимодействия между плазмоидом и поставщиком данных можно отобразить графически (рис. 2).</div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">[[Изображение:LXF110 87 1.png|200px|thumb|center|Рис. 2. Взаимодействие плазмоида с поставщиком данных.]]</ins></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Метод dataUpdated() в классе нашего апплета реализован просто:</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Метод dataUpdated() в классе нашего апплета реализован просто:</div></td></tr>
<tr><td colspan="2" class="diff-lineno">Строка 269:</td>
<td colspan="2" class="diff-lineno">Строка 289:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>апплет перерисовывает свое окно (метод paintInterface() выводит значения переменных m_mf и m_bs).</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>апплет перерисовывает свое окно (метод paintInterface() выводит значения переменных m_mf и m_bs).</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">[[Изображение:LXF110 87 2.png|200px|thumb|Рис. 3. Утилита Add Widgets.]]</ins></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Остановимся подробнее на классе Plasma::DataEngine::Data. Он</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Остановимся подробнее на классе Plasma::DataEngine::Data. Он</div></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div>создан на основе ассоциативного контейнера QHash (LXF102). Для</div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div>создан на основе ассоциативного контейнера QHash (<ins class="diffchange diffchange-inline">[[</ins>LXF102<ins class="diffchange diffchange-inline">:Qt4|LXF102]]</ins>). Для</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>извлечения данных из контейнера мы используем метод value().</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>извлечения данных из контейнера мы используем метод value().</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Первый аргумент – ключ (у нас – название источника данных), второй</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Первый аргумент – ключ (у нас – название источника данных), второй</div></td></tr>
<tr><td colspan="2" class="diff-lineno">Строка 286:</td>
<td colspan="2" class="diff-lineno">Строка 307:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Add Widgets (рис 3).</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Add Widgets (рис 3).</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins style="color: red; font-weight: bold; text-decoration: none;">[[Изображение:LXF110 87 3.png|200px|thumb|Рис. 4. Плазмоид MemInfo.]]</ins></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Плазмоиды, возможно, не самая увлекательная, но весьма оригинальная черта новой версии KDE. В следующий же раз мы займемся</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Плазмоиды, возможно, не самая увлекательная, но весьма оригинальная черта новой версии KDE. В следующий же раз мы займемся</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>вещами не увлекательными и не оригинальными, но необходимыми –</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>вещами не увлекательными и не оригинальными, но необходимыми –</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>интернационализацией проектов KDE 4.</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>интернационализацией проектов KDE 4.</div></td></tr>
</table>Yalekshttp://wiki.linuxformat.ru/wiki/index.php?title=LXF110:KDE4&diff=8566&oldid=prevYaleks: Новая: {{Цикл/KDE4}} == Поставщики данных == : ''ЧАСТЬ 3 Плазмоид из проекта прошлого месяца был статичным и только з...2009-08-25T17:12:46Z<p>Новая: {{Цикл/KDE4}} == Поставщики данных == : ''ЧАСТЬ 3 Плазмоид из проекта прошлого месяца был статичным и только з...</p>
<p><b>Новая страница</b></p><div>{{Цикл/KDE4}}<br />
== Поставщики данных ==<br />
: ''ЧАСТЬ 3 Плазмоид из проекта прошлого месяца был статичным и только зря занимал место на рабочем столе. Чтобы быть по-настоящему полезным, апплет должен отображать постоянно меняющиеся сведения – этим сегодня и займется '''Андрей Боровский'''.''<br />
<br />
Идеология разделения данных и интерфейса, заметно изменившая структуру Qt 4, теперь овладела умами разработчиков KDE. Для расширений Plasma предлагается единый<br />
механизм доступа к данным – “data engines”, которые я буду называть «поставщиками данных». Получая данные из разных источников,<br />
поставщики передают их апплетам KDE Plasma (плазмоидам) с помощью унифицированного интерфейса. Следует сразу оговориться, что<br />
этот интерфейс до сих пор не принял законченную форму, так что в<br />
примерах к данной статье мы рассмотрим сразу несколько вариантов,<br />
которые следует применять в KDE 4.0.x и KDE 4.1.x (разумеется, ветка 4.0 уходит в прошлое, но на данный момент это может быть единственный работоспособный вариант KDE 4 для вашего дистрибутива).<br />
Будем надеяться, что интерфейсы libplasma, используемые в KDE<br />
4.1.x, стабилизируются надолго.<br />
<br />
Как отмечалось в предыдущей статье, информационные расширения Plasma используются в основном для отображения данных, меняющихся во времени – нагрузки на систему, сетевого трафика, прогнозов погоды и т.п. (хотя ничто не мешает использовать плазмоиды и<br />
для отображения статических данных, вряд ли пользователи захотят<br />
загромождать свои виртуальные рабочие столы такими апплетами).<br />
В принципе, для создания динамического плазмоида не обязательно<br />
использовать поставщики данных (мы ведь обошлись без них в прошлый раз, когда программировали статический плазмоид!). Можно<br />
организовать обновление с помощью таймера, однако использование поставщиков данных не только более удобно и создает меньшую<br />
нагрузку на систему, но и гарантирует нашему плазмоиду более долгую жизнь и широкое признание.<br />
<br />
Подобно всем расширениям KDE, поставщики данных представляют собой разделяемые библиотеки, экспортирующие несколько классов. Каждый поставщик имеет один или несколько источников данных (data sources). Источники выдают данные в виде пар «ключ – значение», причем один источник может предоставлять несколько таких<br />
пар. Ключ – просто строка латинских символов, а значение может<br />
принадлежать самым разным типам (для его передачи используется<br />
QVariant). Все данные одного поставщика хранятся в глобальной хэш-таблице (контейнер QHash).<br />
<br />
В качестве примера мы рассмотрим поставщик данных, предоставляющий заинтересованным расширениям Plasma информацию о<br />
состоянии оперативной памяти системы (ее мы почерпнем из файла<br />
/proc/meminfo). Данные о нагрузке на память – это как раз тот тип<br />
динамически меняющейся информации, для представления которой<br />
удобно использовать плазмоиды. В частности, наш поставщик данных позволит апплетам получать информацию об объеме свободной<br />
оперативной памяти и количестве выделенных буферов.<br />
<br />
=== Пишем библиотеку поставщика ===<br />
Основной класс поставщика данных должен быть потомком<br />
Plasma::DataEngine, который объявлен в заголовочном файле Plasma/DataEngine (или plasma/dataengine.h). Ниже приведен текст основного класса нашего поставщика данных, TestDataEngine:<br />
<source lang="cpp-qt">class TestDataEngine : public Plasma::DataEngine {<br />
Q_OBJECT<br />
public:<br />
TestDataEngine(QObject* parent, const QVariantList& args);<br />
void init();<br />
protected:<br />
bool sourceRequestEvent(const QString& name);<br />
bool updateSourceEvent(const QString& source);<br />
bool sourceRequested(const QString& name);<br />
bool updateSource(const QString& source);<br />
};</source><br />
Ради обеспечения обратной совместимости класс TestDataEngine<br />
спроектирован по принципу «два в одном». Дело в том, что интерфейс класса Plasma::DataEngine претерпел при переходе от libplasma<br />
1.0.x к libplasma 1.1 некоторые изменения. В обеих версиях библиотеки нам приходится перекрывать два виртуальных метода: один<br />
вызывается системой для создания источника данных, другой – для<br />
обновления данных уже созданного источника. В разных версиях<br />
библиотеки libplasma эти методы именуются по-разному. В старой<br />
версии для регистрации источников данных используется метод<br />
sourceRequested(), а для обновления – метод updateSource(). В новой<br />
версии для тех же целей вызываются методы sourceRequestEvent() и<br />
updateSourceEvent(). В классе TestDataEngine мы реализуем оба набора методов (благо они друг другу не мешают).<br />
<br />
Кроме перечисленных четырех методов, у нашего класса есть еще<br />
конструктор и метод init(). Как следует из названия, система вызывает его для инициализации элементов поставщика данных, которые<br />
нельзя настроить в конструкторе. Перейдем к реализации класса:<br />
<source lang="cpp-qt">TestDataEngine::TestDataEngine(QObject* parent, const QVariantList&args)<br />
: Plasma::DataEngine(parent) {<br />
setMinimumUpdateInterval(1000);<br />
}<br />
void TestDataEngine::init() {<br />
updateSource("MemFree");<br />
updateSource("Buffers");<br />
}<br />
bool TestDataEngine::sourceRequestEvent(const QString &name) {<br />
return updateSourceEvent(name);<br />
}<br />
bool TestDataEngine::sourceRequested(const QString &name) {<br />
return updateSourceEvent(name);<br />
}<br />
bool TestDataEngine::updateSource(const QString &name) {<br />
return updateSourceEvent(name);<br />
}<br />
bool TestDataEngine::updateSourceEvent(const QString &name) {<br />
QFile file("/proc/meminfo");<br />
file.open(QIODevice::ReadOnly);<br />
char line[256];<br />
while (file.readLine(line, 256) != 0) {<br />
QString s = line;<br />
if (s.indexOf(name) >= 0) {<br />
setData(name, s);<br />
file.close();<br />
return true;<br />
}<br />
}<br />
file.close();<br />
return false;<br />
}<br />
K_EXPORT_PLASMA_DATAENGINE(testde, TestDataEngine)<br />
#include "testde.moc"</source><br />
Разбор исходного текста начнем с метода updateSourceEvent(),<br />
поскольку в нем сосредоточено все самое интересное. В единственном параметре этого метода система передает имя требуемого источника данных. Если метод updateSourceEvent() может обновить данные<br />
запрашиваемого источника, он возвращает значение true, в противном случае – false.<br />
<br />
Данные о состоянии памяти в файле /proc/meminfo представлены<br />
в виде пар<br />
ПАРАМЕТР=ЗНАЧЕНИЕ<br />
Наш поставщик рассматривает каждый параметр как отдельный<br />
источник данных, благодаря чему плазмоиды могут получать значения только интересующих их величин, игнорируя все остальное.<br />
Таким образом, количество источников данных, предоставляемых<br />
нашим поставщиком, соответствует количеству параметров в файле /proc/meminfo (на практике мы не делаем доступными все возможные источники данных). Получив имя источника, наш метод<br />
updateSourceEvent() ищет в файле /proc/meminfo строку с соответствующим параметром. Если она найдена, метод возвращает значение true, иначе – false. Сами данные передаются вызывающему приложению с помощью метода setData() класса Plasma::DataEngine. Он<br />
существует в двух перегруженных вариантах. Первый принимает три<br />
параметра – имя источника данных, ключ и значение, второй – два<br />
(имя источника и значение). Имя источника и ключ передаются в<br />
строке QString, сами данные – в параметре типа QVariant.<br />
<br />
Чтобы понять дальнейшее, нужно ясно представлять себе, что<br />
делает метод setData() – а он добавляет данные в глобальную таблицу. Если источник с указанным именем уже существует, связанные с<br />
ним данные обновляются. Если источника не существует, он будет<br />
создан. Далее апплет Plasma извлекает нужные данные из коллекции,<br />
используя имя источника. Таким образом, метод setData() используется как для обновления данных уже существующего источника, так<br />
и для создания нового. В нашем примере для регистрации источников<br />
данных и обновления используется один и тот же код, так что методы<br />
sourceRequestEvent(), sourceRequested(), updateSource() просто вызывают метод updateSourceEvent(). Напомню, что если вы пользуетесь<br />
библиотеками KDE 4.1.x или более поздними, вы можете удалить объявления и реализации методов sourceRequested() и updateSource().<br />
<br />
Регистрация источников данных выполняется в методе init() (так,<br />
по крайней мере, требует KDE 4.0.x). В этом методе мы два раза<br />
вызываем метод updateSourceEvent(), один раз – для параметра<br />
MemFree (свободная память), другой раз – для Buffers. В результате мы создаем два источника данных, MemFree и Buffers, которые<br />
предоставляют доступ к значениям одноименных параметров файла<br />
/proc/meminfo (мы могли бы зарегистрировать больше источников, но<br />
для простоты примера ограничимся этими двумя).<br />
<br />
В конструкторе класса мы вызываем метод<br />
setMinimumUpdateInterval(), который устанавливает минимальный<br />
интервал обновления данных поставщика (в миллисекундах). Это<br />
позволяет нам снизить нагрузку на систему, что особенно важно в тех<br />
случаях, когда получение данных связано с серьезными затратами<br />
ресурсов. Забегая вперед, отметим, что плазмоид может запрашивать<br />
данные и с более высокой частотой, но их фактическое обновление<br />
(вызов метода updateSourceEvent()) будет происходить не чаще, чем<br />
было указано с помощью setMinimumUpdateInterval().<br />
<br />
Макрос K_EXPORT_PLASMA_DATAENGINE() спасает нас от необходимости рутинно объявлять вспомогательные классы, необходимые для экспорта главного класса поставщика данных. Его первый<br />
аргумент – имя поставщика, под которым он будет известен системе<br />
Plasma, второй – имя главного класса.<br />
<br />
Подобно плазмоиду, поставщик данных нуждается в .desktop-файле. Вот как может выглядеть его простой (без интернационализации) вариант для нашего тестового поставщика:<br />
<source lang="ini">[Desktop Entry]<br />
Name=Test Data Engine<br />
Comment=Test Data Engine<br />
Type=Service<br />
X-KDE-ServiceTypes=Plasma/DataEngine<br />
X-KDE-Library=plasma_engine_testde<br />
X-Plasma-EngineName=testde<br />
X-KDE-PluginInfo-Author=Andrei Borovsky<br />
X-KDE-PluginInfo-Email=<br />
X-KDE-PluginInfo-Name=testde<br />
X-KDE-PluginInfo-Version=0.1<br />
X-KDE-PluginInfo-Website=<br />
X-KDE-PluginInfo-Category=Examples<br />
X-KDE-PluginInfo-Depends=<br />
X-KDE-PluginInfo-License=LGPL<br />
X-KDE-PluginInfo-EnabledByDefault=true</source><br />
Параметру X-KDE-ServiceTypes присваивается значение Plasma/DataEngine (поставщик данных Plasma). X-KDE-Library устанавливается равным plasma_engine_testde (наш поставщик данных будет<br />
размещен в библиотеке plasma_engine_testde.so), для X-Plasma-EngineName (имя, под которым поставщик данных будет доступен<br />
Plasma) выбрано значение testde. Наконец, для X-KDE-PluginInfo-EnabledByDefault установлено значение true.<br />
<br />
Нам осталось написать файл CMakeLists.txt для сборки нашего<br />
проекта. Вот он:<br />
<source lang="text">project(plasma-testde)<br />
set(CMAKE_INSTALL_PREFIX /usr/)<br />
find_package(Qt4 REQUIRED)<br />
find_package(KDE4 REQUIRED)<br />
include(KDE4Defaults)<br />
find_package(Plasma REQUIRED)<br />
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})<br />
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}<br />
${KDE4_INCLUDES} )<br />
set(testde_engine_SRCS testde.cpp)<br />
kde4_add_plugin(plasma_engine_testde ${testde_engine_SRCS})<br />
target_link_libraries(plasma_engine_testde ${KDE4_KDECORE_LIBS}<br />
${PLASMA_LIBS})<br />
install(TARGETS plasma_engine_testde DESTINATION ${PLUGIN_INSTALL_DIR})<br />
install(FILES plasma-dataengine-testde.desktop DESTINATION<br />
${SERVICES_INSTALL_DIR})</source><br />
Как видно, он похож на мета-проект из предыдущей статьи, так<br />
что подробно останавливаться на его содержимом мы не будем.<br />
Отметим только необходимость правильно указывать директории<br />
для установки библиотеки поставщика. По умолчанию переменная<br />
PLUGIN_INSTALL_DIR, используемая в команде install(), содержит<br />
значение /lib/kde4/. Подобно этому, переменная SERVICES_INSTALL_DIR (которая указывает путь для установки .desktop-файла) содержит<br />
/share/kde4/services/. Если эти значения устраивают вашу систему,<br />
то все в порядке (для проверки выясните, существует ли в вашей<br />
системе директория /share/kde4/services/ и хранит ли она уже установленные .desktop-файлы). В моей системе KDE ищет файлы расширений в директориях с теми же именами, что заданы по умолчанию,<br />
но расположенных в /usr, поэтому в самом начале я меняю значение<br />
переменной CMAKE_INSTALL_PREFIX.<br />
<br />
Прежде чем писать для нашего поставщика данных апплет Plasma,<br />
желательно убедиться, что он работает корректно (иначе мы не<br />
будем знать, где ошиблись – в поставщике или в плазмоиде). Для<br />
тестирования поставщика tested мы можем воспользоваться утилитой plasmaengineexplorer, которая играет в разработке поставщиков<br />
данных ту же роль, что и plasmoidviewer для плазмоидов.<br />
<br />
После завершения сборки поставщика данных testde командуем<br />
sudo make install<br />
далее перезапускаем Plasma с помощью последовательности<br />
kquitapp plasma<br />
plasma<br />
и открываем утилиту plasmaengineexplorer (рис. 1).<br />
<br />
Раскрывающийся список в верхней части окна утилиты содержит<br />
перечень установленных поставщиков данных. Если установка нашего<br />
поставщика прошла успешно, в этом списке должен быть пункт testde.<br />
В окне plasmaengineexplorer отображается список источников данных,<br />
предоставляемых выбранным поставщиком. В нашем случае это два<br />
источника данных, зарегистрированных в методе init(). Над окном с<br />
перечнем источников данных расположены строка ввода и наборный<br />
счетчик. Если вы хотите проверить, как выполняется обновление данных, укажите в строке ввода имя источника данных, а в наборном<br />
счетчике – интервал обновления, и щелкните кнопку Request.<br />
<br />
=== Красивый интерфейс ===<br />
Для окончательной победы над апплетами Plasma нам осталось написать плазмоид, использующий данные, предоставляемые поставщиком testde. Я назвал его meminfo, а полные исходные тексты можно<br />
найти в файле meminfo.tar.gz на LXFDVD. На момент написания этой<br />
статьи разработчики KDE еще не представили руководства по созданию плазмоидов такого типа, хотя wiki-затравка на сайте проекта<br />
висит уже не первый месяц. Описание, которое приводится ниже,<br />
составлено исключительно на основе исходных текстов плазмоидов,<br />
поставляемых вместе с KDE. Возможно, используемые здесь интерфейсы будут меняться со временем. Перед тем, как сесть писать<br />
собственный плазмоид, я советую вам изучить заголовочные файлы plasma/dataengine.h и plasma/dataenginemanager.h из последнего<br />
релиза KDE, а также исходные тексты плазмоидов из него же (апплеты и поставщики данных содержатся в пакетах kdebase-workspace).<br />
<br />
Для подключения к поставщику данных необходимо создать<br />
экземпляр его класса. Мы делаем это с помощью метода dataEngine(),<br />
которому передается имя поставщика (альтернативный вариант –<br />
вызов метода loadDataEngine() объекта Plasma::DataEngineManager).<br />
В любом случае, вы получите указатель на объект класса<br />
Plasma::DataEngine, который на самом деле является объектом главного класса загруженного поставщика данных (напомню, что все они<br />
происходят от Plasma::DataEngine). В разных версиях KDE эти методы<br />
работают несколько по-разному, так что не бойтесь экспериментировать. Если для получения указателя на объект поставщика класса<br />
вы используете метод loadDataEngine(), то для повторного получения<br />
указателя на этот объект следует вызывать метод dataEngine() объекта Plasma::DataEngineManager. После того, как мы получили доступ к<br />
главному объекту поставщика данных, можно подключиться к нему,<br />
используя метод connectSource(). Вот как это делается в плазмоиде<br />
meminfo:<br />
<source lang="cpp-qt">void MemInfo::init() {<br />
dataEngine("testde")->connectSource("MemFree", this, 1000);<br />
dataEngine("testde")->connectSource("Buffers", this, 1000);<br />
}</source><br />
Мы подключаемся к обоим источникам данных, которые регистрирует поставщик. В первом аргументе метода connectSource()<br />
передается имя источника данных, во втором – указатель на объект<br />
плазмоида, выполняющий визуализацию данных (то есть на главный<br />
объект плазмоида, тот, что происходит от Plasma::Applet). В третьем<br />
параметре указывается интервал обновления данных в миллисекундах. В нашем примере плазмоид задает тот же интервал обновления,<br />
что и в поставщике данных, хотя это, напомню, необязательно. Что<br />
происходит в процессе вызова метода connectSource()? Главный объект загруженного поставщика данных связывает один из своих сигналов со слотом dataUpdated(), каковой мы должны реализовать в главном классе плазмоида. Напомню, что слоты в Qt могут вызваться по<br />
имени и списку аргументов, как и любые методы, помеченные макросом Q_INVOKABLE. Благодаря этому поставщик данных может вызывать слот, у которого нет прототипа в базовом классе Plasma::Applet.<br />
Заголовок слота dataUpdated() должен выглядеть так:<br />
<source lang="cpp-qt">void dataUpdated(const QString&, const Plasma::DataEngine::Data&)</source><br />
В первом аргументе слоту dataUpdated() передается имя источника обновляемых данных, во втором – ссылка на объект<br />
Plasma::DataEngine::Data, который содержит сами данные. Схему взаимодействия между плазмоидом и поставщиком данных можно отобразить графически (рис. 2).<br />
<br />
Метод dataUpdated() в классе нашего апплета реализован просто:<br />
<source lang="cpp-qt">void MemInfo::dataUpdated(const QString &name, const<br />
Plasma::DataEngine::Data &data){<br />
m_mf = data.value("MemFree", m_mf).toString();<br />
m_bs = data.value("Buffers", m_bs).toString();<br />
update();<br />
}</source><br />
Мы извлекаем обновленные данные из контейнера<br />
Plasma::DataEngine::Data и помещаем их в переменные типа QString<br />
m_mf и m_bs, а затем вызываем метод update(), в результате чего<br />
апплет перерисовывает свое окно (метод paintInterface() выводит значения переменных m_mf и m_bs).<br />
<br />
Остановимся подробнее на классе Plasma::DataEngine::Data. Он<br />
создан на основе ассоциативного контейнера QHash (LXF102). Для<br />
извлечения данных из контейнера мы используем метод value().<br />
Первый аргумент – ключ (у нас – название источника данных), второй<br />
(необязательный) аргумент – переменная, значение которой должен<br />
вернуть метод value() в случае, если с заданным ключом не связаны<br />
никакие данные. Иначе говоря, в строке<br />
<source lang="cpp-qt">m_mf = data.value("MemFree", m_mf).toString();</source><br />
мы присваиваем переменной m_mf значение, связанное с ключом<br />
“MemFree”, если оно существует; в противном же случае сохраняем<br />
прежнее значение m_mf. Все это нужно постольку, поскольку при<br />
каждом вызове dataUpdate() методу передаются лишь те данные,<br />
обновление которых послужило его причиной, то есть данные только<br />
одного источника. С остальными элементами плазмоида мы уже знакомы. После применения CMake сборка апплета выполняется командой make, а установка – sudo make install (после этого следует перезапустить KDE). Мы можем посмотреть, как работает апплет, в окне<br />
plasmoidviewer или добавить его на рабочий стол с помощью утилиты<br />
Add Widgets (рис 3).<br />
<br />
Плазмоиды, возможно, не самая увлекательная, но весьма оригинальная черта новой версии KDE. В следующий же раз мы займемся<br />
вещами не увлекательными и не оригинальными, но необходимыми –<br />
интернационализацией проектов KDE 4.</div>Yaleks