首页 Qt Qt Creator 插件开发(12):添加新的编辑器(续四)

Qt Creator 插件开发(12):添加新的编辑器(续四)

8 2.1K

Core::IEditor

HtmlEditor类实现了IEditor接口。这个接口提供一个编辑器组件,用于编辑 HTML 文件。我们还需要将一个HtmlFile实例与其关联起来:

#ifndef HTMLEDITOR_H
#define HTMLEDITOR_H

#include <coreplugin/editormanager/ieditor.h>

struct HtmlEditorData;

class QToolBar;

class HtmlEditorWidget;
class HtmlFile;

namespace HtmlEditorConstants
{
    const char* const C_HTMLEDITOR_MIMETYPE = "text/html";
    const char* const C_HTMLEDITOR          = "HTML Editor";
};

class HtmlEditor : public Core::IEditor
{
    Q_OBJECT
public:
    HtmlEditor(HtmlEditorWidget* editorWidget);
    ~HtmlEditor();
    bool createNew(const QString& /*contents*/ = QString());
    QString displayName() const;
    QString id() const { return HtmlEditorConstants::C_HTMLEDITOR; }
    IEditor* duplicate(QWidget* /*parent*/);
    bool duplicateSupported() const;
    Core::IFile* file();
    bool isTemporary() const;
    const char* kind() const;
    bool open(const QString& fileName = QString());
    bool restoreState(const QByteArray& /*state*/);
    QByteArray saveState() const;
    void setDisplayName(const QString &title);
    QWidget* toolBar();
    QWidget* widget();
    Core::Context context() const;

protected slots:
    void slotTitleChanged(const QString& title) { setDisplayName(title); }

private:
    HtmlEditorData* d;
};

struct HtmlEditorData
{ 
    HtmlEditorData() : editorWidget(0), file(0) { }
    HtmlEditorWidget* editorWidget;
    QString displayName;
    HtmlFile* file;
    Core::Context context;
};

#endif // HTMLEDITOR_H

HtmlEditorData保存一个HtmlEditorWidget对象和一个HtmlFile对象。displayName属性用于显示该文档的可视化描述:

struct HtmlEditorData
{ 
    HtmlEditorData() : editorWidget(0), file(0) { }
    HtmlEditorWidget* editorWidget;
    QString displayName;
    HtmlFile* file;
    Core::Context context;
};

构造函数用于初始化HtmlEditorWidget实例。同时,它还创建一个HtmlFile实例,这样就可以将其与HtmlEditor和 widget 关联起来:

HtmlEditor::HtmlEditor(HtmlEditorWidget* editorWidget)
           : Core::IEditor(editorWidget)
{
    d = new HtmlEditorData;
    d->editorWidget = editorWidget;
    d->file = new HtmlFile(this, editorWidget);
    d->context = Core::Context(HtmlEditorConstants::C_HTMLEDITOR);
    connect(d->editorWidget, SIGNAL(contentModified()),
            d->file,         SLOT(modified()));
    connect(d->editorWidget, SIGNAL(titleChanged(QString)),
                             SLOT(slotTitleChanged(QString)));
    connect(d->editorWidget, SIGNAL(contentModified()),
                             SIGNAL(changed()));
}

析构函数不作任何操作,仅仅删除 d 指针:

HtmlEditor::~HtmlEditor()
{
    delete d;
}

下面是一些不需要解释的函数:

QWidget* HtmlEditor::widget()
{
    return d->editorWidget;
}

Core::Context HtmlEditor::context() const
{
    return d->context;
}

Core::IFile* HtmlEditor::file()
{
    return d->file;
}

createNew()函数用于重新设置HtmlEditorWidget的内容以及HtmlFile对象。现在,我们只是简单地忽略contents参数:

bool HtmlEditor::createNew(const QString& contents)
{
    Q_UNUSED(contents);
    d->editorWidget->setContent(QByteArray());
    d->file->setFilename(QString());
    return true;
}

open()函数请求HtmlFile打开一个给定文件名的文件。它假设filename就是一个 HTML 文件的名字:

bool HtmlEditor::open(const QString &fileName)
{
    return d->file->open(fileName);
}

下面的函数则用于返回编辑器的“类型”:

namespace HtmlEditorConstants
{
    const char* const C_HTMLEDITOR_MIMETYPE = "text/html";
    const char* const C_HTMLEDITOR          = "HTML Editor";
};
// ......
const char* HtmlEditor::kind() const
{
    return HtmlEditorConstants::C_HTMLEDITOR;
}

displayName()函数返回的字符串用于显示在打开文件列表中。下面的函数帮助设置和获取这个显示的名字:

QString HtmlEditor::displayName() const
{
    return d->displayName;
}

void HtmlEditor::setDisplayName(const QString& title)
{
    if(d->displayName == title)
        return; 
    d->displayName = title;
    emit changed();
}

下面几个函数仅仅是为了给出纯虚函数的一个默认实现,在我们这个简单的例子中不作任何操作:

bool HtmlEditor::duplicateSupported() const
{
    return false;
}

Core::IEditor* HtmlEditor::duplicate(QWidget* parent)
{
    Q_UNUSED(parent);
    return 0;
}

QByteArray HtmlEditor::saveState() const
{
    return QByteArray();
}

bool HtmlEditor::restoreState(const QByteArray& state)
{
    Q_UNUSED(state);
    return false;
}

QWidget* HtmlEditor::toolBar()
{ 
    return 0;
}

bool HtmlEditor::isTemporary() const
{
    return false;
}

Core::IEditorFactory

HtmlEditorFactory实现了Core::IEditorFactory接口:

#ifndef HTMLEDITORFACTORY_H
#define HTMLEDITORFACTORY_H

#include <coreplugin/editormanager/ieditorfactory.h>

#include "HtmlEditor.h"

struct HtmlEditorFactoryData;

class HtmlEditorPlugin;

class HtmlEditorFactory : public Core::IEditorFactory
{
    Q_OBJECT
public:
    HtmlEditorFactory(HtmlEditorPlugin* owner);
    ~HtmlEditorFactory();
    QStringList mimeTypes() const;
    QString kind() const;
    Core::IEditor* createEditor(QWidget* parent);
    Core::IFile* open(const QString &fileName);
    QString id() const { return QString("HTML Editor Factory ID"); }
    QString displayName() const { return QString("HTML Editor Factory"); }
private:
    HtmlEditorFactoryData* d;
};

struct HtmlEditorFactoryData
{
    HtmlEditorFactoryData()
        : kind(HtmlEditorConstants::C_HTMLEDITOR)
    {
        mimeTypes << QString(HtmlEditorConstants::C_HTMLEDITOR_MIMETYPE);
    }

    QString kind;
    QStringList mimeTypes;
};

#endif // HTMLEDITORFACTORY_H

HtmlEditorFactoryData用于保存HtmlEditorFactory类的私有成员变量。注意,构造函数将其 mime-types 初始化为HtmlEditorConstants::C_HTMLEDITOR_MYMETYPE;同时,我们也设置了 editor 的类型,这个类型同前面所说的HtmlEditor的类型是一致的:

struct HtmlEditorFactoryData
{
    HtmlEditorFactoryData()
        : kind(HtmlEditorConstants::C_HTMLEDITOR)
    {
        mimeTypes << QString(HtmlEditorConstants::C_HTMLEDITOR_MIMETYPE);
    }

    QString kind;
    QStringList mimeTypes;
};

下面几个函数则无需过多解释:

HtmlEditorFactory::HtmlEditorFactory(HtmlEditorPlugin* owner)
                  :Core::IEditorFactory(owner)
{
    d = new HtmlEditorFactoryData;
}

HtmlEditorFactory::~HtmlEditorFactory()
{
    delete d;
}

QStringList HtmlEditorFactory::mimeTypes() const
{
    return d->mimeTypes;
}

QString HtmlEditorFactory::kind() const
{
    return d->kind;
}

还记得我们前面说过,IFileIEditor是关联在一起的。open()函数就是返回正在处理这个文件名指定的IFile实例。如果没有,则会创建一个新的编辑器用于处理这个文件,同时将IFile返回。如果要全部理解这个过程,可以查阅Core::EditorManager::openEditor()函数的实现:

Core::IFile* HtmlEditorFactory::open(const QString& fileName)
{
    Core::EditorManager* em = Core::EditorManager::instance();
    Core::IEditor* iface = em->openEditor(fileName, d->kind);
    return iface ? iface->file() : 0;
}

下面的函数用于创建和返回HtmlEditor实例:

Core::IEditor* HtmlEditorFactory::createEditor(QWidget* parent)
{
    HtmlEditorWidget* editorWidget = new HtmlEditorWidget(parent);
    return new HtmlEditor(editorWidget);
}

实现插件

在前面的章节中,我们已经知道了实现插件的方法。现在我们使用和前面一样的方法实现HtmlEditorPlugin插件类。唯一的区别是initialize()函数的实现:

bool HtmlEditorPlugin::initialize(const QStringList& args, QString *errMsg)
{
    Q_UNUSED(args);

    Core::ICore* core = Core::ICore::instance();
    Core::MimeDatabase* mdb = core->mimeDatabase();
    if(!mdb->addMimeTypes("text-html-mimetype.xml", errMsg))
        return false;
    addAutoReleasedObject(new HtmlEditorFactory(this));

    return true;
}

最后,按照我们前面所写的过程去编译吧!

附件下载:HtmlEditor 插件文件

8 评论

Brian 2011年11月15日 - 17:05

你好,我想用Qt creator的plugin framework自己写一个软件,Coreplugin要自己定制,其他的功能用插件实现,但是程序不能启动,可以指点下吗,thanks!

回复
DevBean 2011年11月15日 - 20:55

具体也不大清楚,只能看看再说啦~

回复
fengyun_52 2011年12月13日 - 11:51

目前是否有剥离好的 plugin framework?
qt creator 采用的是 LGPL 许可,直接使用这样的源码做闭源的商业软件是否侵权?
或者,我将采用此框架的软件同样基于 LGPL 许可发布,那么为这个软件开发的插件是否可以闭源?

回复
DevBean 2011年12月14日 - 17:31

目前是否有剥离好的 plugin framework?
-- 没有,至少官方没有。如果需要只能自己处理,或者自己重新实现。
qt creator 采用的是 LGPL 许可,直接使用这样的源码做闭源的商业软件是否侵权?
-- “直接”使用,我是说“直接”,也就是把 LGPL 的代码直接放进你自己的闭源代码中,这是不允许的。但是,LGPL 没有那么严格,我们可以自己创建一层 wrapper,那么,只要把这层 wrapper 开源,而调用 wrapper 的闭源代码不需要开源。

回复
小马 2011年12月31日 - 00:01

你好,我在编译附件文件时遇到下面错误,不知是什么原因,麻烦给瞧下,谢谢。
HtmlEditor.cpp: In constructor 'HtmlEditor::HtmlEditor(HtmlEditorWidget*)':
HtmlEditor.cpp:11:46: error: cannot allocate an object of abstract type 'HtmlFile'
HtmlFile.h:13:7: note: because the following virtual functions are pure within 'HtmlFile':
..\..\qt-creator\src\plugins/coreplugin/ifile.h:87:18: note: virtual bool Core::IFile::save(QString*, const QString&, bool)
..\..\qt-creator\src\plugins/coreplugin/ifile.h:100:18: note: virtual bool Core::IFile::reload(QString*, Core::IFile::ReloadFlag, Core::IFile::ChangeType)
mingw32-make.exe[1]: *** [debug/HtmlEditor.o] Error 1

回复
DevBean 2011年12月31日 - 10:00

请注意 Qt Creator 的版本。现在 Qt Creator 的代码很不稳定。文章中使用的是 2.2.1,最新版 2.4 中就增加了新的纯虚函数。所以如果你要给其他版本的 Qt Creator 编写插件,需要自行修改相关代码。

回复
王显灿 2016年8月29日 - 16:49

您好,我用的QT版本是5.7。我用的QT中没有wibkit或webkitwidget。在QT5.7中应该用什么代替呢

回复
豆子 2016年8月30日 - 09:24

Qt 5.7 使用的是新的 webengine 模块

回复

回复 DevBean 取消回复

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2