cmake-plugin: 添加基于源代码构建的版本更新检查插件,源代码与构建部分有修改

1. 使用 cmake/modules/config.h.in 模板生成 config.h
2.开启 CMAKE_INCLUDE_CURRENT_DIR 以便用于引入当前源代码目录相对的构建目录中的 config.h
3. 在源代码 main.cpp 中引入 config.h 并 setApplicationVersion
This commit is contained in:
zinface 2023-03-22 09:35:05 +08:00
parent 0415bf2506
commit a2f9673737
13 changed files with 750 additions and 2 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.5.1)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

View File

@ -5,6 +5,10 @@
# 1. Notepad--
# 2. Notepad--
# Notepad--
configure_file(cmake/modules/config.h.in
${CMAKE_BINARY_DIR}/config.h @ONLY)
if(TRUE)
# Notepad--
set(QRC_SOURCES src/RealCompare.qrc)

View File

@ -0,0 +1 @@
#define NOTEPAD_VERSION "v@PROJECT_VERSION@"

View File

@ -138,6 +138,11 @@ int main(int argc, char *argv[])
a.setApplicationDisplayName(c_strTitle);
a.setApplicationName(c_strTitle);
#include <config.h>
#ifdef NOTEPAD_VERSION
a.setApplicationVersion(NOTEPAD_VERSION);
#endif //NOTEPAD_VERSION
QStringList arguments = QCoreApplication::arguments();
//目前就三种

View File

@ -11,5 +11,6 @@ if(TRUE)
# opencc 项目(基于 git)
add_subdirectory(opencc-demo-plugin)
#
add_subdirectory(versionUpdate)
endif(TRUE)

View File

@ -0,0 +1,90 @@
# version-update/CMakeLists.txt
#
# 使
#
# version-update
# version-update -> your plugin name
set(LOCAL_PLUGIN_NAME "version-update")
# version-update
# version-update
# 1. version-update
# 2. version-update
if(TRUE)
# version-update
spark_aux_source_paths(LocalSources
.
StatusWidget
)
spark_add_library(${LOCAL_PLUGIN_NAME} SHARED ${LocalSources})
target_include_directories(${LOCAL_PLUGIN_NAME} PRIVATE
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/cceditor
${PROJECT_SOURCE_DIR}/src/qscint/src
${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
)
# target_link_libraries(${LOCAL_PLUGIN_NAME} QSci)
target_link_QSci(${LOCAL_PLUGIN_NAME})
if(USE_QT6)
# target_link_qt6_Core5Compat(${LOCAL_PLUGIN_NAME}) # : Qt6 使 Core5Compat Qt5
# target_link_qt6_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt6_XmlPatterns(${LOCAL_PLUGIN_NAME}) # Bug
else()
# target_link_qt5_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt5_XmlPatterns(${LOCAL_PLUGIN_NAME})
endif(USE_QT6)
# Notepad-- plugin
set_target_properties(${LOCAL_PLUGIN_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
LIBRARY_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
ARCHIVE_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin)
# bin/plugin 每个位置或许都不一样(特别是 Linux)
# install(TARGETS ${LOCAL_PLUGIN_NAME} DESTINATION bin/plugin)
endif(TRUE)
# ----------------- version-update ----------------- #
if(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
else()
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
# QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
endif(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
if(UNIX)
# Unix/Linux
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
)
endif(UNIX)
# # ----------------- version-update ----------------- #
# spark_add_library_path(StatusWidget StatusWidget)
# target_link_qt5(StatusWidget)
# # ----------------------------------------------------------------
# target_link_StatusWidget(${LOCAL_PLUGIN_NAME})

View File

@ -0,0 +1,264 @@
#include "statuswidget.h"
#include "ui_statuswidget.h"
#include <QPropertyAnimation>
StatusWidget::StatusWidget(QWidget *parent, StatusWidget::EnterDirection in, StatusWidget::LeaveDirection out) :
QWidget(parent),
ui(new Ui::StatusWidget),
parent(parent),
animation(new QPropertyAnimation(this, "pos")),
oldPos(this->pos()),
inDirection(in),
outDirection(out),
hasMouse(false),
isLeaveOut(true) // 默认为已经离开时
{
ui->setupUi(this);
ui->widget->setGeometry(this->geometry());
// 自身初始化(图标)
initializeIcon();
// const QRect parentGeometry = parent->geometry();
// QRect localGeometry = this->geometry();
// int parentWidget = parentGeometry.width();
// int parentHeight = parentGeometry.height();
// localGeometry.setX(parentGeometry.width() - geometry().width());
// setGeometry(localGeometry);
// parent->x();
// 动画事件与初始化
// 设置使用动画的控件
animation->setTargetObject(this);
// 设置动画效果
animation->setEasingCurve(QEasingCurve::InOutQuart);
// 设置目标控件的属性名称
animation->setPropertyName("pos");
// 设置动画时间
animation->setDuration(1000);
// 在动画时进行重绘
connect(animation, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value){
update();
});
connect(animation, SIGNAL(finished()), this, SLOT(onAnimationDone()));
// connect(animation, SIGNAL(()), this, SLOT(onAnimationDone()));
// 动画事件显示超时与初始化
setTimeout(1500);
connect(&showTimeout, &QTimer::timeout, this, [=](){
// 鼠标存在于此窗口的标志?
if (hasMouse) return ;
// 没有鼠标存在于此窗口表示可以移出
stop();
showTimeout.stop();
});
}
StatusWidget::~StatusWidget()
{
delete ui;
}
void StatusWidget::initializeIcon()
{
QSize iconSize = this->ui->icon->size();
QPixmap iconPixmap= QPixmap(":/images/images/icon.png").scaled(iconSize);
ui->icon->setPixmap(iconPixmap);
}
void StatusWidget::setIcon(QPixmap iconPixmap)
{
ui->icon->setPixmap(iconPixmap);
}
QPixmap StatusWidget::getIcon() {
return ui->icon->pixmap()->copy();
}
void StatusWidget::setShowMessage(QString title, QString message)
{
ui->title->setText(title);
ui->message->setText(message);
}
void StatusWidget::setTimeout(int timeoutMsec)
{
showTimeout.setInterval(timeoutMsec);
}
void StatusWidget::setDirection(StatusWidget::EnterDirection in, LeaveDirection out) {
this->inDirection = in;
this->outDirection = out;
}
void StatusWidget::algorithmDirection(QPoint &before, QPoint &after, int direction)
{
int parentX = parent->x();
int parentY = parent->y();
int parentWidth = parent->width();
int parentHeight = parent->height();
// 预留边缘空间
int spaceGap = 10;
// before
int beforeX, beforeY,
// after
afterX, afterY;
// 方位计算,详细/精确扩展?// 这里是不完全的设计形式,如果你想使用不同的方案请另行设计
// 上进只有右上,
if (direction >= TopOut) oldPos = this->pos();
switch (direction) {
// 进入?
case TopIn: // 从上面进入,起始位置为 x(不变)y(小于父)
beforeX = afterX = parentWidth - this->width() - spaceGap;
beforeY = 0 - this->height() - spaceGap;
afterY = 0 + spaceGap;
break;
case LeftIn: // 从左面进入,起始位置为 x(小于父)y(不变)
beforeY = afterY = this->y();
beforeX = parentX - this->x();
afterX = parentX + this->x() + spaceGap;
break;
case RightIn: // 从左面进入,起始位置为 x(大于父)y(不变)
beforeY = afterY = (outDirection == TopOut) ? spaceGap : parentHeight - this->height() - spaceGap;
beforeX = parentWidth + this->width() + spaceGap;
afterX = parentWidth - this->width() - spaceGap;
break;
case BottomIn: // 从下面进入,起始位置为 x(不变)y(大于父)
beforeX = afterX = parentWidth - this->width() - spaceGap;
beforeY = parentHeight + this->height();
afterY = parentHeight - this->height() - spaceGap;
break;
// 离开?
case TopOut: // 从上面离开,起始位置为 x(不变)y(小于父)
beforeX = afterX = this->x();
beforeY = this->y();
afterY = 0 - this->height() - spaceGap;
break;
case LeftOut: // 从左面离开,起始位置为 x(小于父)y(不变)
beforeY = afterY = this->y();
beforeX = this->x();
afterX = 0 - this->width() - spaceGap;
break;
case RightOut: // 从左面离开,起始位置为 x(大于父)y(不变)
beforeY = afterY = this->y();
beforeX = this->x();
afterX = parentWidth + spaceGap;
break;
case BottomOut: // 从下面离开,起始位置为 x(不变)y(大于父)
beforeX = afterX = this->x();
beforeY = this->y();
afterY = parentHeight + this->height() + spaceGap;
break;
}
// New ?
// switch (direction) {
// case TopIn: // 从上面进入,起始位置为 x(不变)y(小于父与其自身高)
// beforeX = afterX = this->x();
// beforeY = 0 - this->height() - spaceGap;
// afterY = spaceGap;
// break;
// case LeftIn: // 从左面进入,起始位置为 x(小于父与其自身宽)y(不变)
// beforeY = afterY = this->y();
// beforeX = 0 - this->x() - this->width();
// afterX = parentX + this->x() + spaceGap;
// break;
// case RightIn: // 从左面进入,起始位置为 x(大于父与其宽)y(不变)
// beforeY = afterY = this->y();
// beforeX = parentX + parentWidth + this->x() + spaceGap;
// afterX = parentWidth - this->x() - spaceGap;
// break;
// case BottomIn: // 从下面进入,起始位置为 x(不变)y(大于父与其高)
// beforeX = afterX = this->x();
// beforeY = parentHeight + this->height();
// afterY = parentHeight - this->height() - spaceGap;
// break;
// }
before.setX(beforeX);
before.setY(beforeY);
after.setX(afterX);
after.setY(afterY);
}
// 进入动画
void StatusWidget::start(bool autoLeave) {
// 计算方向
QPoint before, after;
algorithmDirection(before, after, inDirection);
animation->setStartValue(before);
animation->setEndValue(after);
animation->start();
// 超时定时器启动?
if (autoLeave) showTimeout.start();
show(); // 默认情况启动动画时应该是显示的
// hide(); //默认情况完成动画时并且不在窗口内时应该是隐藏的
}
// 离开动画
void StatusWidget::stop()
{
QPoint before, after;
algorithmDirection(before, after, outDirection);
animation->setStartValue(before);
animation->setEndValue(after);
animation->start();
// 超时定时器停止?
showTimeout.stop();
}
void StatusWidget::on_close_clicked()
{
this->stop();
}
void StatusWidget::onAnimationDone()
{
// 不知道逻辑是否严谨
// if (x() >= parent->width()) {
// isLeaveOut = true;
// } else {
// isLeaveOut = false;
// }
// isLeaveOut = x() >= parent->width(); // 如果默认情况在移动未完成时,这个可能不会成立
// 如果默认情况在移动未完成时,这个可能不会成立
// 判断是否在右边
// isLeaveOut = false;
isLeaveOut |= (y() <= parent->y() - height() && x() > 0 && x() < parent->width());
isLeaveOut |= (y() >= parent->height() && x() > 0 && x() < parent->width());
isLeaveOut |= (x() <= parent->width() - width() && y() > 0 && y() < parent->height());
isLeaveOut |= (x() >= parent->width() + width() && y() > 0 && y() < parent->height());
if (!isLeaveOut) {
hide();
} else {
// show(); // ?
}
}
void StatusWidget::enterEvent(QEvent *event)
{
hasMouse = true;
}
void StatusWidget::leaveEvent(QEvent *event)
{
hasMouse = false;
}

View File

@ -0,0 +1,98 @@
#ifndef STATUSWIDGET_H
#define STATUSWIDGET_H
#include <QTimer>
#include <QWidget>
namespace Ui {
class StatusWidget;
}
class QPropertyAnimation;
class StatusWidget : public QWidget
{
Q_OBJECT
public:
// Entering and leaving
// enum EnterLeaveDirection {
// typedef void(*AlgorithDirctionFunc)(QPoint &before, QPoint &after, int direction);
enum EnterDirection {
TopIn = 0,
LeftIn,
RightIn,
BottomIn,
};
enum LeaveDirection {
TopOut = 4,
LeftOut,
RightOut,
BottomOut,
};
// AlgorithDirctionFunc algorithDirectionFunc;
// typedef EnterLeaveDirection EnterDirection;
// typedef EnterLeaveDirection LeaveDirection;
public:
explicit StatusWidget(QWidget *parent = nullptr, enum EnterDirection in = RightIn, enum LeaveDirection out = RightOut);
~StatusWidget();
///
/// \brief initializeIcon
///
void initializeIcon();
///
/// \brief setIcon
/// \param iconPixmap
///
void setIcon(QPixmap iconPixmap);
QPixmap getIcon();
///
/// \brief 消息设置
/// \param title 标题
/// \param message 消息
///
void setShowMessage(QString title, QString message);
// 方位设置与计算
void setTimeout(int timeoutMsec);
void setDirection(EnterDirection in, LeaveDirection out);
void algorithmDirection(QPoint &before, QPoint &after, int direction);
public slots:
void start(bool autoLeave = true);
void stop();
private slots:
void on_close_clicked();
void onAnimationDone();
private:
Ui::StatusWidget *ui;
QWidget *parent;
QPropertyAnimation *animation;
QPoint oldPos;
EnterDirection inDirection;
LeaveDirection outDirection;
QTimer showTimeout;
bool hasMouse;
bool isLeaveOut;
// QWidget interface
protected:
void enterEvent(QEvent *event) override;
void leaveEvent(QEvent *event) override;
// QWidget interface
protected:
// void mouseMoveEvent(QMouseEvent *event) override;
};
#endif // STATUSWIDGET_H

View File

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StatusWidget</class>
<widget class="QWidget" name="StatusWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>275</width>
<height>75</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>275</width>
<height>75</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QWidget" name="widget" native="true">
<property name="styleSheet">
<string notr="true">QWidget{
background-color: rgba(40, 44, 52,150);
border-color: rgba(40, 44, 52,150);
color: rgb(255, 255, 255);
}
QLabel{
background-color: rgba(40, 44, 52,0);
}
</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="3" rowspan="2">
<widget class="QPushButton" name="close">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgba(254, 254, 254, 0);
color: rgb(255, 255, 255);
border-color: rgba(255, 255, 255, 0);
selection-color: rgb(65, 239, 255);</string>
</property>
<property name="text">
<string>x</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="icon">
<property name="minimumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">border-image: url(:/images/images/icon.png)</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="message">
<property name="text">
<string>消息</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="title">
<property name="font">
<font>
<pointsize>13</pointsize>
<kerning>true</kerning>
</font>
</property>
<property name="text">
<string>消息标题</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,81 @@
#include "ndd_plugin_implement.h"
#include "ui_ndd_plugin_implement.h"
#include <qsciscintilla.h>
#include "StatusWidget/statuswidget.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QApplication>
#include <QDesktopServices>
NddPluginImplement::NddPluginImplement(QWidget *parent, QsciScintilla *pEdit) : QMainWindow (parent)
, ui(new Ui::NddPluginImplement)
, currentEdit(pEdit)
{
ui->setupUi(this);
StatusWidget *statusWidget = new StatusWidget(currentEdit);
statusWidget->setShowMessage("提示", "正在检查更新");
statusWidget->setDirection(StatusWidget::TopIn, StatusWidget::RightOut);
statusWidget->start(false);
statusWidget->show();
statusWidget->setIcon(QIcon::fromTheme("notepad--").pixmap(32,32));
statusWidget->setStyleSheet("border-radius: 8px");
QNetworkAccessManager manager;
QEventLoop loop;
QJsonDocument document;
connect(&manager, &QNetworkAccessManager::finished, this, [&](QNetworkReply *reply){
if (reply->error() == QNetworkReply::NetworkError::NoError) {
int statusCode = reply->attribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute).toInt();
qDebug() << "[Notepad--]: 请求状态: " << statusCode;
if (statusCode == 301) {
QUrl redirectionUrl = reply->attribute(QNetworkRequest::Attribute::RedirectionTargetAttribute).toUrl();
qDebug() << "[Notepad--]: 请求被重定向: (" << redirectionUrl.toString() << ")";
manager.get(QNetworkRequest(redirectionUrl));
// tempFilePath = saveHttpImageToTemplateFile(redirectionUrl.toString());
} else {
qDebug() << "[Notepad--]: 请求被确认";
QByteArray byteArray;
byteArray = reply->readAll();
if(!byteArray.isNull()) {
document = QJsonDocument::fromJson(byteArray);
}
loop.quit();
}
} else {
loop.quit();
}
});
QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("https://gitee.com/api/v5/repos/cxasm/notepad--/releases/latest")));
loop.exec();
if (!document.isEmpty()) {
QJsonObject obj = document.object();
if (obj.contains("tag_name")) {
QString kv = obj.value("tag_name").toString();
QString currentVersion = qApp->applicationVersion();
if (currentVersion.compare(kv) != 0) {
statusWidget->setShowMessage("版本更新", QString("%1 > %2").arg(currentVersion).arg(kv));
QDesktopServices::openUrl(QUrl("https://gitee.com/cxasm/notepad--/releases/latest"));
} else {
statusWidget->setShowMessage("提示", "检查完成,没有任何更新");
}
qDebug() << "[Notepad--]: 版本确认 -" << kv;
} else {
}
} else {
qDebug() << "[Notepad--]: 版本未未确认";
statusWidget->setShowMessage("提示", "检查更新失败");
}
}
NddPluginImplement::~NddPluginImplement()
{
}

View File

@ -0,0 +1,23 @@
#ifndef NDD_PLUGIN_IMPLEMENT_H
#define NDD_PLUGIN_IMPLEMENT_H
#include <QMainWindow>
class QsciScintilla;
namespace Ui {
class NddPluginImplement;
}
class NddPluginImplement : public QMainWindow
{
Q_OBJECT
public:
explicit NddPluginImplement(QWidget *parent = nullptr, QsciScintilla *pEdit = nullptr);
~NddPluginImplement();
private:
QsciScintilla *currentEdit;
Ui::NddPluginImplement *ui;
};
#endif // NDD_PLUGIN_IMPLEMENT_H

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NddPluginImplement</class>
<widget class="QMainWindow" name="NddPluginImplement">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>379</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>27</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,11 @@
#include <qobject.h>
#include <qstring.h>
#include <include/pluginGl.h>
#include <functional>
#include <qsciscintilla.h>
#include "ndd_plugin_implement.h"
NOTEPAD_PLUGIN_METADATA_IDENTIFY("检查更新", "v0.1", "zinface", "Notepad-- 版本检查", "");
NOTEPAD_PLUGIN_METADATA_IMPLEMENT(NddPluginImplement, false);