Вводная
В Qt Creator сейчас существует мощный текстовый редактор с поддержкой Generic Highlighting на основе katepart. Было бы странным писать свой текстовый редактор, когда рядом есть такой инструмент. Вопрос только как его использовать. Решением этого вопроса и займемся
Плагин TextEditor
В стандартную поставку Creator входит плагин TextEditor, который собственно и является редактором для любых текстовых файлов, он поддерживает подсветку синтаксиса на основе katepart, цветовую гамму, задаваемую в настройках и много других полезных фич.
Из него нас интересуют классы TextEditor::PlainTextEditor и TextEditor::PlainTextEditorEditable. От этих классов мы и будем наследовать наши. Но для начала подготовим проект к переходу на таббированый интерфейс и интеграцию TextEditor'а.
Подготовка
При использовании TextEditor отпадает необходимость в использовании реализаций интерфейсов IFile и IEditor, так как их предоставляет TextEditor.
Следующим шагом нам надо вынести основной виджет редактора отдельно, а дерево отдельно. Переименуем класс дерева в XmlEditorTreeView и создадим новый класс XmlEditorWidget, который будет отнаследован от QTabWidget. Вновь созданный класс и будет основным виджетом нашего обновленного редактора.
Также нам необходимо добавить TextEditor в зависимости в XmlTreePlugin.pluginspec.
Интеграция TextEditor
Для базовой интеграции нам необходимо отнаследовать класс TextEditor::PlainTextEditor, который будет заниматься визуальной частью редактирования (он в свою очередь в глубине иерархии отнаследован от обычного QPlainTextEdit). Также нам понадобится наследник TextEditor::PlainTextEditorEditable, который сам по себе является наследником IEditor (то есть именно этот класс у нас и будет возвращаться из XmlEditorFactory).
Наследник TextEditor::PlainTextEditor
Класс XmlSourceEditor практически не отличается от своего предка, за исключением одной особенности. Дело в том что по умолчанию Editable возвращает указатель на свой Editor при вызове метода widget() (который используется для получения виджета, который необходимо отобразить в качестве редактора). Нам нужно отобразить не Editor, а наш виджет с табами. Для этого нам надо переопределить виртуальный метод createEditableInterface() и вернуть из него экземпляр нашего Editable (о котором речь пойдет дальше), который будет знать о вышележащем виджете с табами.
Наследник TextEditor::PlainTextEditorEditable
Класс XmlSourceEditorEditable знает о том, что на самом деле редактором является не его Editor, а наш виджет с табами и все операции (открытие, создание нового документа и тд) проводит именно через наш виджет.
Доработка напильником
Для минимально рабочей версии нам осталось всего ничего: поменять метод createEditor() в нашей фабрике и научить виджет с табами правильно работать с двумя редакторами (текстовый и дерево).
В случае фабрики все просто и состоит из трех строк:
Core::IEditor *XmlEditorFactory::createEditor(QWidget *parent) {
XmlEditorWidget *editorWidget = new XmlEditorWidget(parent); TextEditor::TextEditorSettings::instance()->initializeEditor( editorWidget->sourceEditor()); return editorWidget->sourceEditor()->editableInterface(); }
|
Нам необходимо:
- Реализовать методы открытия файла и создания нового
- Обновлять контент вкладок, только когда это необходимо (когда он поменялся на другой вкладке) Правильно реагировать на переключение вкладок
- Правильно удалить наш виджет
Методы открытия и создания:
bool XmlEditorWidget::createNew(const QString &contents) {
bool result = d->sourceEditor->createNew(contents); if (result) d->treeView->setContent( d->sourceEditor->document()->toPlainText()); d->contentModifiedFromLastTabSwitch = false; d->sourceEditor->baseTextDocument()-> document()->setModified(false); return result; }
bool XmlEditorWidget::open(const QString &fileName) {
bool result = d->sourceEditor->open(fileName); if (result) d->treeView->setContent( d->sourceEditor->document()->toPlainText()); d->contentModifiedFromLastTabSwitch = false; d->sourceEditor->baseTextDocument()-> document()->setModified(false); return result; }
|
void XmlEditorWidget::slotTreeContentModified() {
d->contentModifiedFromLastTabSwitch = true; d->sourceEditor->baseTextDocument()-> document()->setModified(true); }
void XmlEditorWidget::slotSourceContentModified() {
d->contentModifiedFromLastTabSwitch = true; }
|
void XmlEditorWidget::slotCurrentChanged(int index) {
if (d->contentModifiedFromLastTabSwitch) { switch (index) { case SourceEditor: d->sourceEditor->setPlainText(d->treeView->content()); d->sourceEditor->baseTextDocument()-> document()->setModified(true); break; case TreeViewEditor: d->treeView->setContent( d->sourceEditor->document()->toPlainText()); default: break; } } d->contentModifiedFromLastTabSwitch = false; }
|
XmlEditorWidget::~XmlEditorWidget() {
disconnect(SIGNAL(currentChanged(int))); this->clear(); d->sourceEditor->setParent(0); delete d; }
|
Заключение
По сути на этом все, теперь у нас есть две вкладки (дерево и исходники), которые связаны между собой и предоставляют минимальный функционал по редактированию.
Комментариев нет:
Отправить комментарий