编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

QT CREATOR 插件开发:添加新的编辑器(一)

wxchong 2024-09-03 02:13:54 开源技术 7 ℃ 0 评论

Qt Creator 最基本的功能是一个文本编辑器。在此基础之上,Qt Creator 还提供了编辑 UI 文件、QRC 文件、PRO/PRI 文件以及 EXE/DLL/SO 文件的功能。

从本节开始,我们将开始尝试开发一些实际的插件,理解如何为我们特有的文件格式提供编辑器。这里,我们选择 HTML 格式。我们的插件将使我们能够从本地文件系统中加载 HTML 文件,并且能够查看和编辑。下面就是我们的插件完成后的行为:

核心类和接口

为了支持新的编辑器类型,我们需要:

  • 实现一个插件类(实现Core::IPlugin接口),暴露出一个“编辑器工厂”。前面我们已经介绍过如何创建插件,实现Core::IPlugin接口。
  • 实现这个“编辑器工厂”,也就是Core::IEditorFactory接口。这个接口提供了帮助创建特定格式编辑器对象的函数。
  • 实现编辑器,也就是Core::IEditor接口。这个接口提供了用于辅助编辑一种文件格式(例如 HTML、ODF 等)的函数。编辑器必须提供访问它所要显示或者编辑的文件的函数。
  • 实现接口Core::IFile。该接口用于帮助数据加载或保存。

在后面的内容中,我们将依次了解上述各个接口的含义以及如何实现这些接口。

Core::IFile

Core::IFile接口将文件操作从用户界面抽象出来,提供用于加载和保存文件的虚函数(一般会以文件名作为参数)。我们可以将文件看做具有 mime-tyle、“modified” 和 “read-only” 等标记位的对象。Core::IFile接口在 src/plugins/coreplugin/ifile.h 中声明:

#ifndef IFILE_H
#define IFILE_H

#include "core_global.h"
#include <QtCore/QObject>

namespace Core {

class MimeType;

class CORE_EXPORT IFile : public QObject
{
    Q_OBJECT

public:
    // This enum must match the indexes of the reloadBehavior widget
    // in generalsettings.ui
    enum ReloadSetting {
        AlwaysAsk = 0,
        ReloadUnmodified = 1,
        IgnoreAll = 2
    };

    enum Utf8BomSetting {
        AlwaysAdd = 0,
        OnlyKeep = 1,
        AlwaysDelete = 2
    };

    enum ChangeTrigger {
        TriggerInternal,
        TriggerExternal
    };

    enum ChangeType {
        TypeContents,
        TypePermissions,
        TypeRemoved
    };

    enum ReloadBehavior {
        BehaviorAsk,
        BehaviorSilent
    };

    enum ReloadFlag {
        FlagReload,
        FlagIgnore
    };

    IFile(QObject *parent = 0) : QObject(parent) {}
    virtual ~IFile() {}

    virtual bool save(const QString &fileName = QString()) = 0;
    virtual QString fileName() const = 0;

    virtual QString defaultPath() const = 0;
    virtual QString suggestedFileName() const = 0;
    virtual QString mimeType() const = 0;

    virtual bool isModified() const = 0;
    virtual bool isReadOnly() const = 0;
    virtual bool isSaveAsAllowed() const = 0;

    virtual ReloadBehavior reloadBehavior(ChangeTrigger state,
                                          ChangeType type) const = 0;
    virtual void reload(ReloadFlag flag, ChangeType type) = 0;
    virtual void rename(const QString &newName) = 0;

    virtual void checkPermissions() {}

signals:
    void changed();

    void aboutToReload();
    void reloaded();
};

} // namespace Core

#endif // IFILE_H

【领QT开发教程学习资料,点击下方链接莬费领取↓↓,先码住不迷路~】

点击这里:「链接」

或许你会问:“我们已经有QFile,作为文件操作的一种抽象,为什么又要设计一个IFile呢?”原因如下:

  • IFile关心的是以文件名为参数,将一个文件的内容加载进一个编辑器 editor 的行为,而QFile仅仅是将文件内容加载到一个QByteArray对象;
  • IFile需要在用户在编辑器中修改了文件内容的时候发出modified()信号,需要注意的是,此时的文件修改并没有写入磁盘;而QFile只有在文件内容写入磁盘时才会发出bytesWritten()信号;
  • IFile需要处理一个在磁盘被修改的文件如何重新加载到编辑器中,而QFile不需要处理这种问题

我们会在后面的章节中详细探讨如何实现Core::IFile接口。

Core::IEditor

Core::IEditor接口用于提供编辑不同类型文件的编辑器。这个接口位于 src/plugins/coreplugin/editormanager/ieditor.h 中:

#ifndef IEDITOR_H
#define IEDITOR_H

#include <coreplugin/core_global.h>
#include <coreplugin/icontext.h>
#include <QtCore/QMetaType>

namespace Core {

class IFile;

class CORE_EXPORT IEditor : public IContext
{
    Q_OBJECT
public:

    IEditor(QObject *parent = 0) : IContext(parent) {}
    virtual ~IEditor() {}

    virtual bool createNew(const QString &contents = QString()) = 0;
    virtual bool open(const QString &fileName = QString()) = 0;
    virtual IFile *file() = 0;
    virtual QString id() const = 0;
    virtual QString displayName() const = 0;
    virtual void setDisplayName(const QString &title) = 0;

    virtual bool duplicateSupported() const = 0;
    virtual IEditor *duplicate(QWidget *parent) = 0;

    virtual QByteArray saveState() const = 0;
    virtual bool restoreState(const QByteArray &state) = 0;

    virtual int currentLine() const { return 0; }
    virtual int currentColumn() const { return 0; }
    virtual void gotoLine(int line, int column = 0)
    { Q_UNUSED(line) Q_UNUSED(column) }

    virtual bool isTemporary() const = 0;

    virtual QWidget *toolBar() = 0;

    virtual QString preferredModeType() const { return QString(); }

signals:
    void changed();
};

} // namespace Core

Q_DECLARE_METATYPE(Core::IEditor*)

#endif // IEDITOR_H

Core::IEditor主要提供以下功能:

  • 一个编辑器组件(由Core::IEditor::widget()函数返回)。Qt Creator 使用这个组件显示需要编辑的文件的内容;
  • 实现Core::IFile接口的文件(由Core::IEditor::file()函数返回),Qt Creator 使用这个对象触发文件从磁盘加载以及保存到磁盘的操作;
  • 一个自定义的工具条 toolbar,Qt Creator 会在该编辑器可用时自动加载该工具条;
  • 在文件中光标的当前位置(Core::IEditor::currentLine()Core::IEditor::currentColumn()函数)
  • 需要显示在“打开文件”列表的名字。

我们可以通过下面的示意图来理解上面说的这几点:

Core::IEditorFactory

Core::IEditorFactory提供用于创建Core::IEditor实例的函数。Core::IEditor则可以支持 mime-type 文件的编辑。这个接口在 src/plugins/coreplugin/editormanager/ieditorfactory.h 中声明:

#ifndef IEDITORFACTORY_H
#define IEDITORFACTORY_H

#include <coreplugin/ifilefactory.h>

namespace Core {

class IEditor;

class CORE_EXPORT IEditorFactory : public Core::IFileFactory
{
    Q_OBJECT
public:
    IEditorFactory(QObject *parent = 0) : IFileFactory(parent) {}
    virtual ~IEditorFactory() {}

    virtual IEditor *createEditor(QWidget *parent) = 0;
};

} // namespace Core

#endif // IEDITORFACTORY_H

于创建该编辑器实例并将其返回。

Core::MimeDatabase

Core::MimeDatabase类用于保存 Qt Creator 所支持的所有的 mime-type;同时,这个类也可以判断给定文件的 mime-type。例如:

#include <coreplugin/mimedatabase.h>

Core::ICore* core = Core::ICore::instance();
Core::MimeDatabase* mdb = core->mimeDatabase();

Core::MimeType type1 = mdb->findByFile( QFileInfo("C:/Temp/sample.html") );
qDebug("File Type for sample.html = %s", qPrintable(type1.type()));

Core::MimeType type2 = mdb->findByFile( QFileInfo("C:/Temp/TextEdit/Main.cpp") );
qDebug("File Type for Main.cpp = %s", qPrintable(type2.type()));

Core::MimeType type3 = mdb->findByFile( QFileInfo("C:/Temp/TextEdit/TextEdit.pro") );
qDebug("File Type for TextEdit.pro = %s", qPrintable(type3.type()));

当我们运行上面代码时,我们会得到如下结果:

File Type for sample.html = text/plain
File Type for Main.cpp = text/x-c++src
File Type for TextEdit.pro = text/plain

Core::MimeDatabase利用文件后缀名、glob 模式以及“魔数”来判断给定的一个文件的 mime-type。不过此时,我们不去深究MimeDatabase是如何实现的,我们只需要知道可以获取文件的 mime-type 就好了。

正如前文所述,Core::IEditorFactory接口提供某一特定 mime-type 的编辑器(实现了Core::IEditor的类)的实例。那么,下面我们来解释一下,对于给定的文件名,Qt Creator 如何找到合适的Core::IEditorFactory的:

  1. 用户使用“文件->打开”命令选择一个文件;
  2. Qt Creator 使用Core::MimeDatabase识别选定文件的 mime-type;
  3. Qt Creator 遍历所有的Core::IEditorFactory实现,找到支持第 2 步所识别出的 mime-type 的 editor-factory;
  4. Qt Creator 请求该 editor factory 创建一个编辑器实例(Core::IEditor实现);
  5. Core::IEditor::widget()返回的组件显示在 Qt Creator 的主窗口;
  6. 调用Core::IEditor::open()函数,打开第 1 步选择的文件。

添加新的 mime-type

如果我们要添加新文件类型的编辑器,就需要向Core::MimeDatabase注册 mime-type。有很多种机制都可以实现注册新的 mime-type,这里我们使用最简单的方式:利用 XML 文件。

假设我们要注册 text/html mime-type,并且关联 *.html 文件名。我们需要创建一个 XML 文件,然后命名为 text-html-mimetype.xml。

<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
    <mime-type type="text/html">
        <sub-class-of type="text/plain"/>
        <comment>HTML File</comment>
        <glob pattern="*.html"/>
    </mime-type>
</mime-info>

我们利用这个 XML 文件,通过Core::MimeDatabase::addMimeTypes()函数注册新的 mime-type。所需代码示例如下:

Core::ICore* core = Core::ICore::instance();
Core::MimeDatabase* mdb = core->mimeDatabase();
QString errMsg;
bool success = mdb->addMimeTypes("text-html-mimetype.xml", errMsg);

一旦注册成功,Qt Creator 就会将所有 *.html 文件名映射成 text/plain mime-type。

【领QT开发教程学习资料,点击下方链接莬费领取↓↓,先码住不迷路~】

点击这里:「链接」


原文:https://www.devbean.net/2011/10/qtcreator-plugin-develop-8/

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表