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;
} 还记得我们前面说过,IFile与IEditor是关联在一起的。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 评论
你好,我想用Qt creator的plugin framework自己写一个软件,Coreplugin要自己定制,其他的功能用插件实现,但是程序不能启动,可以指点下吗,thanks!
具体也不大清楚,只能看看再说啦~
目前是否有剥离好的 plugin framework?
qt creator 采用的是 LGPL 许可,直接使用这样的源码做闭源的商业软件是否侵权?
或者,我将采用此框架的软件同样基于 LGPL 许可发布,那么为这个软件开发的插件是否可以闭源?
目前是否有剥离好的 plugin framework?
-- 没有,至少官方没有。如果需要只能自己处理,或者自己重新实现。
qt creator 采用的是 LGPL 许可,直接使用这样的源码做闭源的商业软件是否侵权?
-- “直接”使用,我是说“直接”,也就是把 LGPL 的代码直接放进你自己的闭源代码中,这是不允许的。但是,LGPL 没有那么严格,我们可以自己创建一层 wrapper,那么,只要把这层 wrapper 开源,而调用 wrapper 的闭源代码不需要开源。
你好,我在编译附件文件时遇到下面错误,不知是什么原因,麻烦给瞧下,谢谢。
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
请注意 Qt Creator 的版本。现在 Qt Creator 的代码很不稳定。文章中使用的是 2.2.1,最新版 2.4 中就增加了新的纯虚函数。所以如果你要给其他版本的 Qt Creator 编写插件,需要自行修改相关代码。
您好,我用的QT版本是5.7。我用的QT中没有wibkit或webkitwidget。在QT5.7中应该用什么代替呢
Qt 5.7 使用的是新的 webengine 模块