-
Notifications
You must be signed in to change notification settings - Fork 8
Плагины
Разработка QReal и QReal:Robots долгое время шла в отдельных бранчах, из QReal:Robots была вырезана вся функциональность, к роботам не относящаяся. Постепенно ветки начали сильно отличаться, так что автоматически перекладывать изменения из одной в другую уже не получалось, кроме того, перекладывать изменения вообще часто забывали. Сложившаяся ситуация фактически представляла собой один большой копипаст --- поправив баг в одной версии, надо было вручную внести эти же изменения в другую. Чтобы это исправить, было решено расширить понятие "плагин" в QReal, чтоб можно было весь код, относящийся к роботам, вынести в отдельный плагин, подключаемый к общей части.
- Весь относящийся к QReal код должен иметь возможность храниться в одной ветке репозитория, для реализации новой технологии на базе QReal не должно требоваться изменений в общей части.
- Функциональность, не нужная конкретной технологии, должна быть скрыта или убрана из релиза, относящегося к этой технологии, вообще. Например, в роботах не используется SVN, соответственно, в QReal:Robots SVN не должен нигде даже упоминаться, чтобы не вызывать вопросов у учителей и школьников. Аналогично с загадочными для многих кнопками "сгенерировать в HaSCoL", тем более, без редактора HaSCoL всё равно ничего сгенерировать нельзя.
- Плагин должен иметь возможность сам вызывать функциональность общей части, например, для подсветки текущего исполняемого элемента.
- Плагин должен иметь возможность настраивать внешний вид пользовательского интерфейса, чтобы, например, в QReal:Robots заголовок окна был QReal:Robots, а не QReal, или менять сплешскрин. Если подключено одновременно несколько плагинов с такими возможностями, пользователь должен иметь возможность выбрать, с чем он сейчас работает.
Основная идея новых плагинов, или плагинов-инструментов состоит в том, что они создают кнопки, пункты меню и т.д., цепляют к ним свои обработчики и передают в пользовательский интерфейс с указанием куда их добавить. Так что при подключении плагина на панели инструментов появляются новые кнопки, нажав на которые пользователь вызывает какой-то код из плагина, который может делать практически что угодно.
Поскольку код плагинов вынужден использовать код из общей части, например класс Id, QReal стал более модульным. На диаграмме показаны компоненты, собираемые в отдельные бинарники. Стрелки --- зависимости по сборке.

- qrkernel содержит классы, используемые повсюду в системе, такие как Id и Exception. Эту компоненту включают все остальные (почти, qrxc её пока не использует)
- qrutils содержит код, который может быть полезен в нескольких компонентах. Например, вспомогательные классы для работы с xml или записи в файлы. Сюда же выносятся общие части подсистем, используемых в разных плагинах, например, базовая часть парсера, чтобы она была доступна везде, где может потребоваться парсер. Достаточно большие такие подсистемы должны стать отдельными компонентами.
- qrrepo --- репозиторий. Используется всеми, кому нужны нарисованные пользователем диаграммы, то есть практически всеми. Плагины обычно получают доступ к репозиторию не напрямую, а через модели qrgui, чтобы графический интерфейс знал о вносимых плагинами изменениях.
- qrgui --- "основная программа", пользовательский интерфейс и система управления плагинами. На диаграмме плагины и qrgui не связаны, потому что qrgui грузит плагины динамически и собирается независимо, но в реальности qrgui и плагины тесно связаны, причём в обе стороны. Описание интерфейсов, по которым общаются qrgui и плагины, ниже.
- editorGenerator, metaEditor, robotsInterpreter, robotsEditor и т.д. --- плагины. Часть из них --- плагины-редакторы, собираемые из метамоделей, часть --- плагины-инструменты, рукописные. Эти два вида плагинов имеют разные интерфейсы и обрабатываются qrgui по-разному. Плагины-редакторы --- это плагины в старом смысле слова, редакторы визуальных языков. Плагины-инструменты предоставляют некоторую функциональность, регистрируемую в qrgui и вызываемую пользователем.
- qrxc, qrmc --- компиляторы метамоделей. Первый генерирует код на С++ по описанию синтаксиса языка в .xml-файле, второй --- по сэйву с метамоделью. Второй существует как библиотека, подключаемая к qrgui (рано или поздно станет честным плагином), и как отдельный исполняемый файл, вызываемый скриптами сборки.
Структура папок теперь выглядит так:
doc -- пользовательская документация, под Windows не собирается по причине https://bugreports.qt.nokia.com//browse/QTBUG-19072
installer -- скрипты сборки инсталлятора
plugins -- папка с плагинами, сюда складываются все плагины, и тулы, и редакторы
android -- редактор для приложений под андроид
metaEditor -- метаредактор
robots -- всё, что относится к роботам
editor -- плагин-редактор
robotsInterpreter -- плагин-инструмент, интерпретатор
thirdparty -- qextSerialPort, нужный для сборки интерпретатора
... -- другие плагины
qrgui -- пользовательский интерфейс
qrkernel -- ядро
qrmc -- QReal Metamodel Compiler, утилита, компилирующая код редактора по сохранённой метамодели
qrrepo -- репозиторий
qrutils -- полезный код
qrxc -- QReal XML Compiler, утилита, компилирующая код редактора по xml-файлу с метамоделью
umlDocumentation -- диаграммы Visual Paradigm с технической документацией (текстовая документация хранится в вики)
Сборка всего вообще начинается с qreal.pro, который включает как подпроекты все подпапки корневой папки, в том числе plugins. В plugins.pro содержится список "технологий", которые нужно собирать. Каждая такая "технология" может состоять из нескольких плагинов, например, роботы --- из редактора и интерпретатора. Если не хочется собирать всё, надо закомментировать в plugins.pro ненужное, но не коммитить. Проекты, перечисленные в plugins.pro, в большинстве случаев тоже содержат другие проекты как подпроекты. В папке plugins есть папки, которые плагинами не являются: commonMetamodels --- метамодели, включаемые плагинами-редакторами, editorsSdk --- общие файлы и скрипты сборки для плагинов-редакторов.
Важное отличие новой системы сборки --- всё собирается в папку bin в корне проекта (а не в qrgui/debug или qrgui/release или просто в qrgui).
С плагинами-редакторами пока ничего не поменялось. Плагины-инструменты используют только то, что лежит в qrgui/toolPluginInterface, при этом то, что лежит собственно в toolPluginInterface --- это интерфейсы, которые плагины реализуют, а то, что лежит в toolPluginInterface/usedInterfaces --- это интерфейсы, реализуемые qrgui, которые плагины используют.
- CustomizationInterface --- интерфейс для настройки внешнего вида пользовательского интерфейса под конкретный плагин. Здесь есть методы для показа/скрытия частей GUI, используемых не везде, например, провязок или обозревателя логической модели.
- PluginConfigurator --- класс-контейнер, содержащий все нужные объекты qrgui для работы плагина. Передаётся в плагин при инициализации, после чего плагин использует его содержимое для общения с qrgui.
- ToolPluginInterface --- интерфейс плагина. Позволяет qrgui получить список действий, выполняемых плагином, и информацию, в какие меню и на какие панели инструментов эти действия добавить. Эта информация хранится в объектах класса ActionInfo. Этот же интерфейс содержит методы, возвращающие виджет конфигурации плагина, который добавляется в окно настроек, метод инициализации плагина, который вызывается qrgui в начале работы, и метод, который возвращает CustomizationInterface.
Итого, что должны предоставлять плагины:
- Список объектов ActionInfo с информацией о действиях, реализуемых плагином.
- Виджет для конфигурации, если он нужен.
Что могут использовать плагины:
- Модели
- Репозиторий
- Подсвечивание исполняемого блока
- ErrorReporter
- Узнать текущую открытую диаграмму
- и т.д., список будет расширяться
Положим, мы хотим создать просто плагин-инструмент, например, кнопку, очищающую репозиторий (см. плагин exterminatus как пример)
-
Заводим в папке plugins новую папку для нового плагина.
-
Создаём там .pro-файл с примерно таким содержимым:
TEMPLATE = lib CONFIG += plugin DESTDIR = ../../bin/plugins/ HEADERS = \ <сюда писать .h-ники плагина> SOURCES = \ <сюда писать .cpp-шники плагина> -
Создаём класс, наследующийся от QObject и qReal::ToolPluginInterface, реализуем в нём ToolPluginInterface, указав там макросы
Q_OBJECT Q_INTERFACES(qReal::ToolPluginInterface) -
В соответствующем этому классу .cpp-шнике пишем после инклудов строчку вида
Q_EXPORT_PLUGIN2(<название нового плагина, какое угодно>, <имя класса плагина, с неймспейсом>) -
Пишем код, реализующий плагин
-
Проверяем, что всё собирается, вызывая qmake и make (или mingw32-make) в папке с .pro-шником. В случае успеха плагин должен появиться в bin/plugins и подключаться к qrgui при запуске.
-
Подключаем новый плагин к сборке, дописав в plugins/plugins.pro строчку вида
<имя папки с плагином>/<имя .pro-шника плагина>.pro \ -
Удаляем папку bin, запускаем сборку с qreal.pro, проверяем, что всё, включая плагин, собралось.
Если мы хотим создать плагин-редактор, собираемый из .xml-ки, шаги будут такие (см. плагин android/editor как пример):
-
Заводим в папке plugins новую папку для нового плагина.
-
Создаём там .pro-файл с примерно таким содержимым:
QREAL_XML = <имя .xml-ки с метамоделью> QREAL_EDITOR_PATH = <путь до папки с плагином от папки plugins, например, android/editor> ROOT = <путь от .pro до корня проекта, например, ../../..> include (<editorsCommon.pri с относительным путём, например, ../../editorsSdk/editorsCommon.pri>) -
Пишем .xml с метамоделью (взяв в качестве примера какой-нибудь существующий редактор)
-
Проверяем, что всё собирается, вызывая qmake и make (или mingw32-make) в папке с .pro-шником. В случае успеха плагин должен появиться в bin/plugins и подключаться к qrgui при запуске.
-
Подключаем новый плагин к сборке, дописав в plugins/plugins.pro строчку вида
<имя папки с плагином>/<имя .pro-шника плагина>.pro \ -
Удаляем папку bin, запускаем сборку с qreal.pro, проверяем, что всё, включая плагин, собралось.