Skip to content
yurii-litvinov edited this page Aug 28, 2011 · 9 revisions

Разработка 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 и плагинами

С плагинами-редакторами пока ничего не поменялось. Плагины-инструменты используют только то, что лежит в qrgui/toolPluginInterface, при этом то, что лежит собственно в toolPluginInterface --- это интерфейсы, которые плагины реализуют, а то, что лежит в toolPluginInterface/usedInterfaces --- это интерфейсы, реализуемые qrgui, которые плагины используют.

  • CustomizationInterface --- интерфейс для настройки внешнего вида пользовательского интерфейса под конкретный плагин. Здесь есть методы для показа/скрытия частей GUI, используемых не везде, например, провязок или обозревателя логической модели.
  • PluginConfigurator --- класс-контейнер, содержащий все нужные объекты qrgui для работы плагина. Передаётся в плагин при инициализации, после чего плагин использует его содержимое для общения с qrgui.
  • ToolPluginInterface --- интерфейс плагина. Позволяет qrgui получить список действий, выполняемых плагином, и информацию, в какие меню и на какие панели инструментов эти действия добавить. Эта информация хранится в объектах класса ActionInfo. Этот же интерфейс содержит методы, возвращающие виджет конфигурации плагина, который добавляется в окно настроек, метод инициализации плагина, который вызывается qrgui в начале работы, и метод, который возвращает CustomizationInterface.

Итого, что должны предоставлять плагины:

  • Список объектов ActionInfo с информацией о действиях, реализуемых плагином.
  • Виджет для конфигурации, если он нужен.

Что могут использовать плагины:

  • Модели
  • Репозиторий
  • Подсвечивание исполняемого блока
  • ErrorReporter
  • Узнать текущую открытую диаграмму
  • и т.д., список будет расширяться

Как создать новый плагин

Положим, мы хотим создать просто плагин-инструмент, например, кнопку, очищающую репозиторий (см. плагин exterminatus как пример)

  1. Заводим в папке plugins новую папку для нового плагина.

  2. Создаём там .pro-файл с примерно таким содержимым:

     TEMPLATE = lib
     CONFIG += plugin
     DESTDIR = ../../bin/plugins/
     HEADERS = \
             <сюда писать .h-ники плагина>
     SOURCES = \
             <сюда писать .cpp-шники плагина>
    
  3. Создаём класс, наследующийся от QObject и qReal::ToolPluginInterface, реализуем в нём ToolPluginInterface, указав там макросы

     Q_OBJECT
     Q_INTERFACES(qReal::ToolPluginInterface)
    
  4. В соответствующем этому классу .cpp-шнике пишем после инклудов строчку вида

     Q_EXPORT_PLUGIN2(<название нового плагина, какое угодно>, <имя класса плагина, с неймспейсом>)
    
  5. Пишем код, реализующий плагин

  6. Проверяем, что всё собирается, вызывая qmake и make (или mingw32-make) в папке с .pro-шником. В случае успеха плагин должен появиться в bin/plugins и подключаться к qrgui при запуске.

  7. Подключаем новый плагин к сборке, дописав в plugins/plugins.pro строчку вида

     <имя папки с плагином>/<имя .pro-шника плагина>.pro \
    
  8. Удаляем папку bin, запускаем сборку с qreal.pro, проверяем, что всё, включая плагин, собралось.

Если мы хотим создать плагин-редактор, собираемый из .xml-ки, шаги будут такие (см. плагин android/editor как пример):

  1. Заводим в папке plugins новую папку для нового плагина.

  2. Создаём там .pro-файл с примерно таким содержимым:

     QREAL_XML = <имя .xml-ки с метамоделью>
     QREAL_EDITOR_PATH = <путь до папки с плагином от папки plugins, например, android/editor>
     ROOT = <путь от .pro до корня проекта, например, ../../..>
    
     include (<editorsCommon.pri с относительным путём, например, ../../editorsSdk/editorsCommon.pri>)
    
  3. Пишем .xml с метамоделью (взяв в качестве примера какой-нибудь существующий редактор)

  4. Проверяем, что всё собирается, вызывая qmake и make (или mingw32-make) в папке с .pro-шником. В случае успеха плагин должен появиться в bin/plugins и подключаться к qrgui при запуске.

  5. Подключаем новый плагин к сборке, дописав в plugins/plugins.pro строчку вида

     <имя папки с плагином>/<имя .pro-шника плагина>.pro \
    
  6. Удаляем папку bin, запускаем сборку с qreal.pro, проверяем, что всё, включая плагин, собралось.

Clone this wiki locally