ukui-menu/ 0000775 0001750 0001750 00000000000 15160463365 011430 5 ustar feng feng ukui-menu/src/ 0000775 0001750 0001750 00000000000 15160463365 012217 5 ustar feng feng ukui-menu/src/windows/ 0000775 0001750 0001750 00000000000 15160463365 013711 5 ustar feng feng ukui-menu/src/windows/menu-main-window.cpp 0000664 0001750 0001750 00000052377 15160463365 017626 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include "menu-main-window.h"
#include "settings.h"
#include "context-menu-manager.h"
#include "security-function-control.h"
#include
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#else
#include
#endif
#include
#include
#include
#include
#include
#include
#define UKUI_PANEL_SETTING "org.ukui.panel.settings"
#define UKUI_PANEL_POSITION_KEY "panelposition"
#define UKUI_PANEL_SIZE_KEY "panelsize"
#define UKUI_PANEL_TYPE_KEY "paneltype"
#define UKUI_DATA_ISLAND_POSITION_KEY "dataislandposition"
#define UKUI_TOPBAR_SIZE_KEY "topbarsize"
#define UKUI_PANEL_LENGTH_KEY "panellength"
namespace UkuiMenu {
void WindowModule::defineModule(const char *uri, int versionMajor, int versionMinor)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
qmlRegisterRevision(uri, versionMajor, versionMinor);
qmlRegisterRevision(uri, versionMajor, versionMinor);
#else
#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
qmlRegisterRevision(uri, versionMajor, versionMinor);
qmlRegisterRevision(uri, versionMajor, versionMinor);
#else
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
qmlRegisterRevision(uri, versionMajor, versionMinor);
qmlRegisterRevision(uri, versionMajor, versionMinor);
#else
qmlRegisterRevision(uri, versionMajor, versionMinor);
#endif
#endif
#endif
}
// ====== PanelSettings ====== //
static std::once_flag onceFlag;
static PanelGSettings* g_instance = nullptr;
static GSettings * m_settings = nullptr;
static GSettingsSchema * m_schema = nullptr;
static const char *m_panelLengthKey = "panellength";
PanelGSettings *PanelGSettings::instance()
{
std::call_once(onceFlag, [ & ] {
g_instance = new PanelGSettings();
});
return g_instance;
}
int PanelGSettings::getPanelLength(QString screenName)
{
if (!m_settings || !m_schema) return -1;
if (!isKeysContain(m_panelLengthKey)) return -1;
QMap map = getPanelLengthMap();
if (!map.contains(screenName)) {
return -1;
}
return map.value(screenName).toInt();
}
PanelGSettings::~PanelGSettings()
{
if (m_settings) {
g_object_unref(m_settings);
}
if (m_schema) {
g_settings_schema_unref(m_schema);
}
g_instance = nullptr;
}
PanelGSettings::PanelGSettings(QObject *parent) : QObject(parent)
{
GSettingsSchemaSource *source;
source = g_settings_schema_source_get_default();
m_schema = g_settings_schema_source_lookup(source, "org.ukui.panel.settings", true);
if (!m_schema) {
m_settings = nullptr;
return;
}
m_settings = g_settings_new_with_path("org.ukui.panel.settings", "/org/ukui/panel/settings/");
}
bool PanelGSettings::isKeysContain(const char *key)
{
if (!m_settings || !m_schema) return false;
gchar **keys = g_settings_schema_list_keys(m_schema);
if (g_strv_contains(keys, key)) {
g_strfreev(keys);
return true;
} else {
g_strfreev(keys);
return false;
}
}
QMap PanelGSettings::getPanelLengthMap()
{
GVariant *gvalue = g_settings_get_value(m_settings, m_panelLengthKey);
GVariantIter iter;
QMap map;
const gchar *key;
size_t str_len;
GVariant *val = NULL;
g_variant_iter_init (&iter, gvalue);
QVariant qvar;
while (g_variant_iter_next (&iter, "{&sv}", &key, &val)) {
if (g_variant_is_of_type(val, G_VARIANT_TYPE_UINT32)) {
qvar = QVariant::fromValue(static_cast(g_variant_get_uint32(val)));
map.insert(key, qvar);
}
}
g_variant_unref(gvalue);
return map;
}
// ====== WindowGeometryHelper ====== //
WindowGeometryHelper::WindowGeometryHelper(QObject *parent) : QObject(parent)
{
initPanelSetting();
// initScreenMonitor();
updateGeometry();
connect(MenuSetting::instance(), &MenuSetting::changed, this, [this] (const QString& key) {
if (key == MENU_WIDTH || key == MENU_HEIGHT) {
updateGeometry();
}
});
}
void WindowGeometryHelper::updateGeometry()
{
if (!m_primaryScreen) {
return;
}
QRect screenRect = m_primaryScreen->geometry(), normalMaskRect, fullRect;
int width = MenuSetting::instance()->get(MENU_WIDTH).toInt();
int height = MenuSetting::instance()->get(MENU_HEIGHT).toInt();
int margin = MenuSetting::instance()->get(MENU_MARGIN).toInt();
//上: 1, 下: 0, 左: 2, 右: 3
switch (m_panelPos) {
default:
case 0: {
fullRect.setTopLeft(screenRect.topLeft());
fullRect.setSize({screenRect.width(), screenRect.height() - m_panelSize});
QSize normalSize(qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height));
normalMaskRect.setTopLeft({margin, fullRect.height() - normalSize.height() - margin});
normalMaskRect.setSize(normalSize);
break;
}
case 1: {
fullRect.setTopLeft({screenRect.x(), screenRect.y() + m_panelSize});
fullRect.setSize({screenRect.width(), screenRect.height() - m_panelSize});
normalMaskRect.setTopLeft({margin, margin});
normalMaskRect.setSize({qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height)});
break;
}
case 2: {
fullRect.setTopLeft({screenRect.x() + m_panelSize, screenRect.y()});
fullRect.setSize({screenRect.width() - m_panelSize, screenRect.height()});
normalMaskRect.setTopLeft({margin, margin});
normalMaskRect.setSize({qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height)});
break;
}
case 3: {
fullRect.setTopLeft(screenRect.topLeft());
fullRect.setSize({screenRect.width() - m_panelSize, screenRect.height()});
QSize normalSize(qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height));
normalMaskRect.setTopLeft({fullRect.width() - normalSize.width() - margin, margin});
normalMaskRect.setSize(normalSize);
break;
}
}
m_normalGeometry = normalMaskRect;
m_fullScreenGeometry = fullRect;
Q_EMIT geometryChanged();
}
void WindowGeometryHelper::initPanelSetting()
{
if (!MenuSetting::instance()->get(FOLLOW_UKUI_PANEL).toBool()) {
return;
}
const QByteArray id(UKUI_PANEL_SETTING);
if (QGSettings::isSchemaInstalled(id)) {
QGSettings *setting = new QGSettings(id, QByteArray(), this);
QStringList keys = setting->keys();
if (keys.contains(UKUI_PANEL_POSITION_KEY)) {
m_panelPos = setting->get(UKUI_PANEL_POSITION_KEY).toInt();
}
if (keys.contains(UKUI_PANEL_SIZE_KEY)) {
m_panelSize = setting->get(UKUI_PANEL_SIZE_KEY).toInt();
}
connect(setting, &QGSettings::changed, this, [this, setting] (const QString& key) {
if (key == UKUI_PANEL_POSITION_KEY || key == UKUI_PANEL_SIZE_KEY) {
m_panelPos = setting->get(UKUI_PANEL_POSITION_KEY).toInt();
m_panelSize = setting->get(UKUI_PANEL_SIZE_KEY).toInt();
updateGeometry();
}
});
}
}
void WindowGeometryHelper::initScreenMonitor()
{
updatePrimaryScreen(QGuiApplication::primaryScreen());
connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, [this] (QScreen *screen) {
updatePrimaryScreen(screen);
updateGeometry();
});
}
void WindowGeometryHelper::updatePrimaryScreen(QScreen *screen)
{
if (!screen) {
return;
}
if (m_primaryScreen) {
m_primaryScreen->disconnect(this);
}
m_primaryScreen = screen;
connect(m_primaryScreen, &QScreen::geometryChanged, this, &WindowGeometryHelper::updateGeometry);
}
const QRect &WindowGeometryHelper::fullScreenGeometry()
{
return m_fullScreenGeometry;
}
const QRect &WindowGeometryHelper::normalGeometry()
{
return m_normalGeometry;
}
const int WindowGeometryHelper::getPanelPos()
{
return m_panelPos;
}
//======MenuWindow======//
MenuWindow::MenuWindow(QWindow *parent) : QQuickView(parent)
{
init();
}
MenuWindow::MenuWindow(QQmlEngine *engine, QWindow *parent)
: QQuickView(engine, parent)
{
init();
}
void MenuWindow::init()
{
initPanelSetting();
connect(MenuSetting::instance(), &MenuSetting::changed, this, [this] (const QString& key) {
if (key == MENU_WIDTH || key == MENU_HEIGHT) {
updateGeometry();
}
});
m_screen = QGuiApplication::primaryScreen();
setScreen(m_screen);
connect(m_screen, &QScreen::geometryChanged, this, &MenuWindow::updateGeometry, Qt::UniqueConnection);
connect(qGuiApp, &QGuiApplication::layoutDirectionChanged, this, &MenuWindow::updateGeometry, Qt::UniqueConnection);
connect(qGuiApp, &QGuiApplication::screenRemoved, this, [&](QScreen *qScreen) {
if(qScreen == screen()) {
activeMenuWindow(false);
}
}, Qt::UniqueConnection);
setTitle(QCoreApplication::applicationName());
setResizeMode(SizeRootObjectToView);
setColor("transparent");
//setWindowState(Qt::WindowMaximized);
setFlags(flags() | Qt::Window | Qt::FramelessWindowHint);
m_windowProxy = new UkuiQuick::WindowProxy(this);
m_windowProxy->setWindowType(UkuiQuick::WindowType::SystemWindow);
// 访问窗口api
rootContext()->setContextProperty("mainWindow", this);
rootContext()->setContextProperty("isLiteMode", GlobalSetting::instance()->get(GlobalSetting::IsLiteMode));
connect(GlobalSetting::instance(), &GlobalSetting::styleChanged, this , [this] (const GlobalSetting::Key& key) {
if (key == GlobalSetting::EffectEnabled) {
Q_EMIT effectEnabledChanged();
} else if (key == GlobalSetting::Transparency) {
Q_EMIT transparencyChanged();
} else if (key == GlobalSetting::IsLiteMode) {
rootContext()->setContextProperty("isLiteMode", GlobalSetting::instance()->get(key));
}
});
updateGeometry();
ContextMenuManager::instance()->setMainWindow(this);
}
void MenuWindow::initPanelSetting()
{
if (!MenuSetting::instance()->get(FOLLOW_UKUI_PANEL).toBool()) {
return;
}
const QByteArray id(UKUI_PANEL_SETTING);
if (QGSettings::isSchemaInstalled(id)) {
m_setting = new QGSettings(id, QByteArray(), this);
QStringList keys = m_setting->keys();
if (keys.contains(UKUI_PANEL_POSITION_KEY)) {
m_panelPos = m_setting->get(UKUI_PANEL_POSITION_KEY).toInt();
}
if (keys.contains(UKUI_PANEL_SIZE_KEY)) {
m_panelSize = m_setting->get(UKUI_PANEL_SIZE_KEY).toInt();
}
if (keys.contains(UKUI_PANEL_TYPE_KEY)) {
m_panelType = m_setting->get(UKUI_PANEL_TYPE_KEY).toInt();
} else {
m_panelType = 0;
}
if (keys.contains(UKUI_DATA_ISLAND_POSITION_KEY)) {
m_dataIslandPosition = m_setting->get(UKUI_DATA_ISLAND_POSITION_KEY).toInt();
}
if (keys.contains(UKUI_TOPBAR_SIZE_KEY)) {
m_topbarSize = m_setting->get(UKUI_TOPBAR_SIZE_KEY).toInt();
}
connect(m_setting, &QGSettings::changed, this, [this] (const QString& key) {
if (key == UKUI_PANEL_POSITION_KEY) {
m_panelPos = m_setting->get(UKUI_PANEL_POSITION_KEY).toInt();
updateGeometry();
} else if (key == UKUI_PANEL_SIZE_KEY) {
m_panelSize = m_setting->get(key).toInt();
updateGeometry();
} else if (key == UKUI_PANEL_TYPE_KEY) {
m_panelType = m_setting->get(UKUI_PANEL_TYPE_KEY).toInt();
updateGeometry();
} else if (key == UKUI_DATA_ISLAND_POSITION_KEY) {
m_dataIslandPosition = m_setting->get(UKUI_DATA_ISLAND_POSITION_KEY).toInt();
updateGeometry();
} else if (key == UKUI_TOPBAR_SIZE_KEY) {
m_topbarSize = m_setting->get(UKUI_TOPBAR_SIZE_KEY).toInt();
updateGeometry();
} else if (key == UKUI_PANEL_LENGTH_KEY) {
updateGeometry();
}
});
}
}
void MenuWindow::updateGeometry()
{
updateCurrentScreenGeometry();
if (m_fullScreenGeometry.isEmpty()) return;
setMinimumSize(m_fullScreenGeometry.size());
setMaximumSize(m_fullScreenGeometry.size());
setGeometry(m_fullScreenGeometry);
m_windowProxy->setPosition(m_fullScreenGeometry.topLeft());
updateGeometryOfMask();
changeWindowBlurRegion( m_maskGeometry.x(), m_maskGeometry.y(), m_maskGeometry.width(), m_maskGeometry.height(), 16);
}
bool MenuWindow::isFullScreen() const
{
return m_isFullScreen;
}
/**
* beforeFullScreenChanged -> (qml)onWidthChanged -> fullScreenChanged
* @param isFullScreen
*/
void MenuWindow::setFullScreen(bool isFullScreen)
{
if (m_isFullScreen == isFullScreen) {
return;
}
Q_EMIT beforeFullScreenChanged();
m_isFullScreen = isFullScreen;
updateGeometryOfMask();
// 更新contentItem尺寸
QEvent event(QEvent::Resize);
QCoreApplication::sendEvent(this, &event);
Q_EMIT fullScreenChanged();
}
void MenuWindow::changeWindowBlurRegion(qreal x, qreal y, qreal w, qreal h, qreal radius)
{
QPainterPath path;
path.addRoundedRect(x, y, w, h, radius, radius);
m_windowProxy->setBlurRegion(true, QRegion(path.toFillPolygon().toPolygon()));
}
void MenuWindow::exitFullScreen()
{
Q_EMIT beforeFullScreenExited();
}
void MenuWindow::exposeEvent(QExposeEvent *event)
{
QQuickView::exposeEvent(event);
}
void MenuWindow::focusOutEvent(QFocusEvent *event)
{
// void QQuickWindow::focusOutEvent(QFocusEvent *ev) { Q_D(QQuickWindow); if (d->contentItem) d->contentItem->setFocus(false, ev->reason()); }
if (event->reason() == Qt::PopupFocusReason) {
return;
}
QQuickView::focusOutEvent(event);
this->setVisible(false);
}
bool MenuWindow::event(QEvent *event)
{
if (event->type() == QEvent::Show) {
if (QX11Info::isPlatformX11()) {
requestActivate();
}
} else if (event->type() == QEvent::MouseButtonPress) {
ContextMenuManager::instance()->closeMenu();
}
return QQuickView::event(event);
}
bool MenuWindow::effectEnabled() const
{
return GlobalSetting::instance()->get(GlobalSetting::EffectEnabled).toBool();
}
double MenuWindow::transparency() const
{
return GlobalSetting::instance()->get(GlobalSetting::Transparency).toDouble();
}
int MenuWindow::panelPos() const
{
return m_panelPos;
}
bool MenuWindow::editMode() const
{
return m_editMode;
}
void MenuWindow::setEditMode(bool mode)
{
if (mode == m_editMode) {
return;
}
m_editMode = mode;
Q_EMIT editModeChanged();
}
void MenuWindow::updateGeometryOfMask()
{
if (m_isFullScreen) {
m_maskGeometry = QRect(0, 0, m_fullScreenGeometry.width(), m_fullScreenGeometry.height());
} else {
m_maskGeometry = m_normalGeometry;
}
setMask(m_maskGeometry);
}
void MenuWindow::updateCurrentScreenGeometry()
{
if (!m_screen || m_screen->geometry().isEmpty()) {
return;
}
// qt的可用区域有问题,暂时使用任务栏尺寸计算
//QRect normalMaskRect, fullRect = screen()->availableGeometry();
QRect normalMaskRect, fullRect = m_screen->geometry();
int width = MenuSetting::instance()->get(MENU_WIDTH).toInt();
int height = MenuSetting::instance()->get(MENU_HEIGHT).toInt();
int margin = MenuSetting::instance()->get(MENU_MARGIN).toInt();
UkuiQuick::WindowProxy::SlideFromEdge slideFromEdge = UkuiQuick::WindowProxy::NoEdge;
bool isMirrored = qGuiApp->layoutDirection() == Qt::LayoutDirection::RightToLeft;
if (m_panelType == 0) {
//经典任务栏
//上: 1, 下: 0, 左: 2, 右: 3
switch (m_panelPos) {
default:
case 0: {
fullRect.adjust(0, 0, 0, -m_panelSize);
QSize normalSize(qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height));
if (isMirrored) {
normalMaskRect.setTopLeft({fullRect.width() - margin - width, fullRect.height() - normalSize.height() - margin});
} else {
normalMaskRect.setTopLeft({margin, fullRect.height() - normalSize.height() - margin});
}
normalMaskRect.setSize(normalSize);
slideFromEdge = UkuiQuick::WindowProxy::BottomEdge;
break;
}
case 1: {
fullRect.adjust(0, m_panelSize, 0, 0);
QSize normalSize(qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height));
if (isMirrored) {
normalMaskRect.setTopLeft({fullRect.width() - margin - width, margin});
} else {
normalMaskRect.setTopLeft({margin, margin});
}
normalMaskRect.setSize(normalSize);
slideFromEdge = UkuiQuick::WindowProxy::TopEdge;
break;
}
case 2: {
fullRect.adjust(m_panelSize, 0, 0, 0);
normalMaskRect.setTopLeft({margin, margin});
normalMaskRect.setSize({qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height)});
slideFromEdge = UkuiQuick::WindowProxy::LeftEdge;
break;
}
case 3: {
fullRect.adjust(0, 0, -m_panelSize, 0);
QSize normalSize(qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height));
normalMaskRect.setTopLeft({fullRect.width() - normalSize.width() - margin, margin});
normalMaskRect.setSize(normalSize);
slideFromEdge = UkuiQuick::WindowProxy::RightEdge;
break;
}
}
} else if (m_panelType == 1) {
//三岛任务栏
if (m_dataIslandPosition == 0) {
fullRect.adjust(0, 0, 0, -m_panelSize);
QSize normalSize(qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height));
if (isMirrored) {
normalMaskRect.setTopLeft({fullRect.width() -
(fullRect.width() - PanelGSettings::instance()->getPanelLength(m_screen->name())) / 2 - width ,
fullRect.height() - normalSize.height() - margin});
} else {
normalMaskRect.setTopLeft({(fullRect.width() - PanelGSettings::instance()->getPanelLength(m_screen->name())) / 2,
fullRect.height() - normalSize.height() - margin});
}
normalMaskRect.setSize(normalSize);
slideFromEdge = UkuiQuick::WindowProxy::BottomEdge;
} else if (m_dataIslandPosition == 1) {
fullRect.adjust(0, m_topbarSize, 0, 0);
QSize normalSize(qMin(fullRect.width() - margin*2, width), qMin(fullRect.height() - margin*2, height));
if (isMirrored) {
normalMaskRect.setTopLeft({fullRect.width() - margin - width, margin});
} else {
normalMaskRect.setTopLeft({margin, margin});
}
normalMaskRect.setSize(normalSize);
slideFromEdge = UkuiQuick::WindowProxy::TopEdge;
}
}
m_normalGeometry = normalMaskRect;
m_fullScreenGeometry = fullRect;
m_windowProxy->slideWindow(slideFromEdge, 0);
Q_EMIT panelPosChanged();
Q_EMIT normalRectChanged();
}
QRect MenuWindow::normalRect() const
{
return m_normalGeometry;
}
void MenuWindow::activeMenuWindow(bool active)
{
if (active == isVisible()) {
return;
}
if (active) {
if (SecurityFunctionControl::instance()->disable()) return;
if (m_screen != UkuiQuick::WindowProxy::currentScreen()) {
if (m_screen) {
m_screen->disconnect(this);
}
m_screen = UkuiQuick::WindowProxy::currentScreen();
this->setScreen(m_screen);
connect(m_screen, &QScreen::geometryChanged, this, &MenuWindow::updateGeometry, Qt::UniqueConnection);
updateGeometry();
}
}
setVisible(active);
}
} // UkuiMenu
ukui-menu/src/windows/menu-main-window.h 0000664 0001750 0001750 00000010540 15160463365 017255 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_MENU_MAIN_WINDOW_H
#define UKUI_MENU_MENU_MAIN_WINDOW_H
#include
#include
#include
#include
#include
#include
#include
namespace UkuiMenu {
class WindowModule final
{
public:
static void defineModule(const char *uri, int versionMajor, int versionMinor);
};
class PanelGSettings : public QObject
{
Q_OBJECT
public:
static PanelGSettings *instance();
int getPanelLength(QString screenName);
~PanelGSettings();
private:
PanelGSettings(QObject *parent = nullptr);
bool isKeysContain(const char* key);
QMap getPanelLengthMap();
};
class WindowGeometryHelper final : public QObject
{
Q_OBJECT
public:
explicit WindowGeometryHelper(QObject *parent = nullptr);
const QRect &normalGeometry();
const QRect &fullScreenGeometry();
const int getPanelPos();
Q_SIGNALS:
void geometryChanged();
private Q_SLOTS:
void updateGeometry();
void updatePrimaryScreen(QScreen *screen);
private:
void initPanelSetting();
void initScreenMonitor();
private:
// 任务栏位置与屏幕:上: 1, 下: 0, 左: 2, 右: 3, 如果为其他值,则说明任务栏不存在
int m_panelPos{4};
int m_panelSize{0};
QScreen *m_primaryScreen{nullptr};
QRect m_normalGeometry;
QRect m_fullScreenGeometry;
};
class MenuWindow : public QQuickView
{
Q_OBJECT
Q_PROPERTY(bool isFullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged)
Q_PROPERTY(bool effectEnabled READ effectEnabled NOTIFY effectEnabledChanged)
Q_PROPERTY(bool editMode READ editMode WRITE setEditMode NOTIFY editModeChanged)
Q_PROPERTY(double transparency READ transparency NOTIFY transparencyChanged)
Q_PROPERTY(int panelPos READ panelPos NOTIFY panelPosChanged)
Q_PROPERTY(QRect normalRect READ normalRect NOTIFY normalRectChanged)
public:
explicit MenuWindow(QWindow *parent = nullptr);
MenuWindow(QQmlEngine* engine, QWindow *parent);
bool isFullScreen() const;
void setFullScreen(bool isFullScreen);
bool editMode() const;
void setEditMode(bool mode);
bool effectEnabled() const;
double transparency() const;
int panelPos() const;
QRect normalRect() const;
void activeMenuWindow(bool active);
Q_INVOKABLE void changeWindowBlurRegion(qreal x, qreal y, qreal w, qreal h, qreal radius = 8);
Q_INVOKABLE void exitFullScreen();
Q_SIGNALS:
void geometryChanged();
void effectEnabledChanged();
void transparencyChanged();
void fullScreenChanged();
void beforeFullScreenChanged();
void beforeFullScreenExited();
void panelPosChanged();
void editModeChanged();
void normalRectChanged();
protected:
void exposeEvent(QExposeEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
bool event(QEvent *event) override;
private:
void init();
void initPanelSetting();
void updateGeometry();
void updateGeometryOfMask();
void updateCurrentScreenGeometry();
private:
// 任务栏位置与屏幕:上: 1, 下: 0, 左: 2, 右: 3, 如果为其他值,则说明任务栏不存在
int m_panelPos{4};
int m_panelSize{48};
int m_panelType{0};
int m_dataIslandPosition{0};
int m_topbarSize{0};
bool m_editMode {false};
bool m_isFullScreen{false};
QRect m_maskGeometry = QRect(0,0,0,0);
QRect m_normalGeometry = QRect(0,0,0,0);
QRect m_fullScreenGeometry = QRect(0,0,0,0);
QGSettings *m_setting {nullptr};
UkuiQuick::WindowProxy *m_windowProxy {nullptr};
QPointer m_screen {nullptr};
};
} // UkuiMenu
#endif //UKUI_MENU_MENU_MAIN_WINDOW_H
ukui-menu/src/extension/ 0000775 0001750 0001750 00000000000 15160463353 014230 5 ustar feng feng ukui-menu/src/extension/context-menu-extension.cpp 0000664 0001750 0001750 00000001506 15160463353 021376 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "context-menu-extension.h"
namespace UkuiMenu {
int ContextMenuExtension::index() const
{
return -1;
}
} // UkuiMenu
ukui-menu/src/extension/widget-extension.h 0000664 0001750 0001750 00000004253 15160463353 017702 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_WIDGET_EXTENSION_H
#define UKUI_MENU_WIDGET_EXTENSION_H
#include
#include
namespace UkuiMenu {
class WidgetMetadata
{
Q_GADGET
public:
enum Key {
Id = 0,
Icon,
Name,
Tooltip,
Version,
Description,
Main,
Type,
Flag,
Data
};
Q_ENUM(Key)
enum TypeValue {
Widget = 0x01, /**> 显示在插件区域 */
Button = 0x02, /**> 显示在侧边栏 */
AppList = 0x04 /**> 显示在应用列表,默认会显示在全屏界面 */
};
Q_ENUM(TypeValue)
Q_DECLARE_FLAGS(Types, TypeValue)
Q_FLAGS(Types)
enum FlagValue {
OnlySmallScreen = 0x01,
OnlyFullScreen = 0x02,
Normal = OnlySmallScreen | OnlyFullScreen
};
Q_ENUM(FlagValue)
Q_DECLARE_FLAGS(Flags, FlagValue)
Q_FLAGS(Flags)
};
typedef QMap MetadataMap;
class WidgetExtension : public QObject
{
Q_OBJECT
public:
explicit WidgetExtension(QObject *parent = nullptr);
virtual int index() const;
virtual MetadataMap metadata() const = 0;
// 兼容老版本
virtual QVariantMap data();
virtual void receive(const QVariantMap &data);
Q_SIGNALS:
void dataUpdated();
};
} // UkuiMenu
Q_DECLARE_METATYPE(UkuiMenu::MetadataMap)
Q_DECLARE_METATYPE(UkuiMenu::WidgetMetadata::TypeValue)
Q_DECLARE_METATYPE(UkuiMenu::WidgetMetadata::FlagValue)
#endif //UKUI_MENU_WIDGET_EXTENSION_H
ukui-menu/src/extension/widget-extension-model.cpp 0000664 0001750 0001750 00000006617 15160463353 021341 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "widget-extension-model.h"
#include "menu-extension-loader.h"
#include
namespace UkuiMenu {
WidgetExtensionModel::WidgetExtensionModel(QObject *parent) : QAbstractListModel(parent)
{
m_widgets = MenuExtensionLoader::instance()->widgets();
for (int i = 0; i < m_widgets.size(); ++i) {
connect(m_widgets.at(i), &WidgetExtension::dataUpdated, this, [i, this] {
Q_EMIT dataChanged(QAbstractListModel::index(i), QAbstractListModel::index(i), {WidgetMetadata::Data});
});
}
}
QModelIndex WidgetExtensionModel::parent(const QModelIndex &child) const
{
return {};
}
int WidgetExtensionModel::rowCount(const QModelIndex &parent) const
{
return m_widgets.count();
}
int WidgetExtensionModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
QVariant WidgetExtensionModel::data(const QModelIndex &index, int role) const
{
if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)) {
return {};
}
int row = index.row();
WidgetExtension *widget = m_widgets.at(row);
auto key = WidgetMetadata::Key(role);
switch (key) {
case WidgetMetadata::Id:
case WidgetMetadata::Icon:
case WidgetMetadata::Name:
case WidgetMetadata::Tooltip:
case WidgetMetadata::Version:
case WidgetMetadata::Description:
case WidgetMetadata::Main:
case WidgetMetadata::Type:
case WidgetMetadata::Flag:
return widget->metadata().value(key, {});
case WidgetMetadata::Data:
return widget->data();
default:
break;
}
return {};
}
QHash WidgetExtensionModel::roleNames() const
{
QHash hash;
hash.insert(WidgetMetadata::Id, "id");
hash.insert(WidgetMetadata::Icon, "icon");
hash.insert(WidgetMetadata::Name, "name");
hash.insert(WidgetMetadata::Tooltip, "tooltip");
hash.insert(WidgetMetadata::Version, "version");
hash.insert(WidgetMetadata::Description, "description");
hash.insert(WidgetMetadata::Main, "main");
hash.insert(WidgetMetadata::Type, "type");
hash.insert(WidgetMetadata::Flag, "flag");
hash.insert(WidgetMetadata::Data, "data");
return hash;
}
WidgetExtension *WidgetExtensionModel::widgetAt(int index) const
{
if (index < 0 || index >= m_widgets.count()) {
return nullptr;
}
return m_widgets.at(index);
}
void WidgetExtensionModel::notify(int index, const QVariantMap &data) const
{
WidgetExtension *widget = widgetAt(index);
if (widget) {
widget->receive(data);
}
}
WidgetExtensionModel *WidgetExtensionModel::instance()
{
static WidgetExtensionModel model;
return &model;
}
} // UkuiMenu
ukui-menu/src/extension/context-menu-manager.h 0000664 0001750 0001750 00000003123 15160463353 020436 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_CONTEXT_MENU_MANAGER_H
#define UKUI_MENU_CONTEXT_MENU_MANAGER_H
#include
#include
#include "context-menu-extension.h"
class QWindow;
class MenuManagerPrivate;
namespace UkuiMenu {
class ContextMenuManager : public QObject
{
Q_OBJECT
public:
static ContextMenuManager *instance();
~ContextMenuManager() override;
Q_INVOKABLE void showMenu(const QString &appid, MenuInfo::Location location, const QString& lid = QString(), const QPoint &point = QPoint());
void showMenu(const DataEntity &data, MenuInfo::Location location, const QString& lid = QString(), const QPoint &point = QPoint());
void setMainWindow(QWindow *mainWindow);
bool closeMenu();
private:
ContextMenuManager();
inline QPoint checkPoint(const QPoint &rawPoint);
private:
MenuManagerPrivate *d {nullptr};
};
} // UkuiMenu
#endif //UKUI_MENU_CONTEXT_MENU_MANAGER_H
ukui-menu/src/extension/context-menu-extension.h 0000664 0001750 0001750 00000004072 15160463353 021044 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_CONTEXT_MENU_EXTENSION_H
#define UKUI_MENU_CONTEXT_MENU_EXTENSION_H
#include
#include
#include "data-entity.h"
namespace UkuiMenu {
class MenuInfo
{
Q_GADGET
public:
enum Location {
AppList = 0, /**< 小屏幕的应用列表 */
Extension, /**< 扩展页 */
FolderPage, /**< 文件夹页面 */
FullScreen, /**< 全屏应用列表 */
Folder, /**< 应用组页面 */
};
Q_ENUM(Location)
};
/**
* @class ContextMenuExtension
*
* 开始菜单应用列表的上下文菜单扩展插件
*/
class ContextMenuExtension
{
public:
virtual ~ContextMenuExtension() = default;
/**
* 控制菜单项显示在哪个位置
* 对于第三方项目们应该选择-1,或者大于1000的值
* @return -1:表示随机放在最后
*/
virtual int index() const;
/**
* 根据data生成action,或者子菜单
*
* @param data app信息
* @param parent action最终显示的QMenu
* @param location 请求菜单的位置
* @param locationId 位置的描述信息,可选的值有:all,category,letterSort和favorite等插件的id
* @return
*/
virtual QList actions(const DataEntity &data, QMenu *parent, const MenuInfo::Location &location, const QString &locationId) = 0;
};
} // UkuiMenu
#endif //UKUI_MENU_CONTEXT_MENU_EXTENSION_H
ukui-menu/src/extension/menu-extension-plugin.cpp 0000664 0001750 0001750 00000001601 15160463353 021204 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "menu-extension-plugin.h"
UkuiMenu::MenuExtensionPlugin::MenuExtensionPlugin(QObject *parent) : QObject(parent)
{
}
UkuiMenu::MenuExtensionPlugin::~MenuExtensionPlugin() = default;
ukui-menu/src/extension/menu-extension-plugin.h 0000664 0001750 0001750 00000003476 15160463353 020665 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_MENU_EXTENSION_PLUGIN_H
#define UKUI_MENU_MENU_EXTENSION_PLUGIN_H
#define UKUI_MENU_EXTENSION_I_FACE_TYPE "UKUI_MENU_EXTENSION"
#define UKUI_MENU_EXTENSION_I_FACE_IID "org.ukui.menu.extension"
#define UKUI_MENU_EXTENSION_I_FACE_VERSION "1.0.2"
#include
namespace UkuiMenu {
class WidgetExtension;
class ContextMenuExtension;
class Q_DECL_EXPORT MenuExtensionPlugin : public QObject
{
Q_OBJECT
public:
explicit MenuExtensionPlugin(QObject *parent = nullptr);
~MenuExtensionPlugin() override;
/**
* 插件的唯一id,会被用于区分插件
* @return 唯一id
*/
virtual QString id() = 0;
/**
* 创建一个Widget扩展
* @return 返回nullptr代表不生产此插件
*/
virtual WidgetExtension *createWidgetExtension() = 0;
/**
* 创建上下文菜单扩展
* @return 返回nullptr代表不生产此插件
*/
virtual ContextMenuExtension *createContextMenuExtension() = 0;
};
} // UkuiMenu
Q_DECLARE_INTERFACE(UkuiMenu::MenuExtensionPlugin, UKUI_MENU_EXTENSION_I_FACE_IID)
#endif //UKUI_MENU_MENU_EXTENSION_PLUGIN_H
ukui-menu/src/extension/widget-model.cpp 0000664 0001750 0001750 00000004263 15160463353 017322 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "widget-model.h"
#include "widget-extension-model.h"
#include
#include
namespace UkuiMenu {
// ====== WidgetModel ====== //
WidgetModel::WidgetModel(QObject *parent) : QSortFilterProxyModel(parent)
{
init();
}
WidgetMetadata::Types WidgetModel::types() const
{
return m_types;
}
void WidgetModel::setTypes(WidgetMetadata::Types types)
{
if (m_types == types) {
return;
}
m_types = types;
invalidateFilter();
}
WidgetMetadata::Flags WidgetModel::flags() const
{
return m_flags;
}
void WidgetModel::setFlags(WidgetMetadata::Flags flags)
{
if (m_flags == flags) {
return;
}
m_flags = flags;
invalidateFilter();
}
bool WidgetModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
bool acceptFlag = m_types.testFlag(index.data(WidgetMetadata::Type).value());
if (acceptFlag) {
return m_flags & index.data(WidgetMetadata::Flag).value();
}
return false;
}
void WidgetModel::init()
{
QSortFilterProxyModel::setSourceModel(WidgetExtensionModel::instance());
// invalidateFilter();
}
void WidgetModel::send(int index, const QVariantMap &data)
{
auto sourceModel = qobject_cast(QSortFilterProxyModel::sourceModel());
if (sourceModel) {
sourceModel->notify(index, data);
}
}
} // UkuiMenu
ukui-menu/src/extension/favorite/ 0000775 0001750 0001750 00000000000 15160463365 016052 5 ustar feng feng ukui-menu/src/extension/favorite/favorite-widget.h 0000664 0001750 0001750 00000002357 15160463353 021327 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_FAVORITE_WIDGET_H
#define UKUI_MENU_FAVORITE_WIDGET_H
#include "../widget-extension.h"
#include "folder-model.h"
namespace UkuiMenu {
class FavoriteWidget : public WidgetExtension
{
Q_OBJECT
public:
explicit FavoriteWidget(QObject *parent = nullptr);
int index() const override;
MetadataMap metadata() const override;
QVariantMap data() override;
void receive(const QVariantMap &data) override;
private:
MetadataMap m_metadata;
QVariantMap m_data;
};
} // UkuiMenu
#endif //UKUI_MENU_FAVORITE_WIDGET_H
ukui-menu/src/extension/favorite/app-favorite-model.cpp 0000664 0001750 0001750 00000043143 15160463365 022256 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "favorites-config.h"
#include "app-favorite-model.h"
#include "favorite-folder-helper.h"
#include "../context-menu-manager.h"
#include
#include
#include
#include
#include
#include
namespace UkuiMenu {
class Q_DECL_HIDDEN AppFavoritesModel::Private
{
public:
explicit Private(AppFavoritesModel *q = nullptr);
~Private();
void init();
QPersistentModelIndex getIndexFromAppId(const QString &id) const;
void addFavoriteApp(const QPersistentModelIndex &modelIndex, const int &index = 0);
void removeFavoriteApp(const QString &appId);
void onAppRemoved(const QModelIndex &parent, int first, int last);
void onAppUpdated(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector());
void updateFavoritesApps(const QModelIndex &sourceIndex);
void onFolderAdded(const int &folderId, int order);
void onFolderDeleted(const int &folderId, const QStringList &apps);
void onFolderAppChanged(const int &folderId, const QString &appId, bool isAdded);
QVector m_favoritesApps; // 已收藏应用在baseModel的对应index
QVector m_folders; // 应用组的唯一Id
QVector m_favoritesFiles; // 收藏文件夹的唯一路径
BasicAppModel *m_sourceModel = nullptr;
QStringList m_items;
private:
AppFavoritesModel *q = nullptr;
};
AppFavoritesModel::Private::Private(AppFavoritesModel* q) : q(q)
{
}
AppFavoritesModel::Private::~Private()
{
}
void AppFavoritesModel::Private::init()
{
m_items = FavoritesConfig::instance().getConfig();
QSet existingItems(m_items.begin(), m_items.end());
QStringList favoritesNeedsAdd;
m_favoritesApps.clear();
for (int i = 0; i < m_sourceModel->rowCount(QModelIndex()); i++) {
const auto index = m_sourceModel->index(i, 0);
const QString id = index.data(DataEntity::Id).toString();
const QString fullId = APP_ID_SCHEME + id;
const int favorite = index.data(DataEntity::Favorite).toInt();
if (favorite > 0) {
QPersistentModelIndex persistentIndex(index);
m_favoritesApps.append(persistentIndex);
if (!existingItems.contains(fullId) && !FavoriteFolderHelper::instance()->containApp(id)) {
favoritesNeedsAdd.append(fullId);
existingItems.insert(fullId);
}
// 处理配置中有,但数据库为未收藏的情况
} else if (existingItems.contains(fullId)) {
QPersistentModelIndex persistentIndex(index);
m_favoritesApps.append(persistentIndex);
m_sourceModel->databaseInterface()->fixAppToFavorite(id, 1);
}
}
// 如果有新增收藏项,更新配置
if (!favoritesNeedsAdd.isEmpty()) {
m_items.append(favoritesNeedsAdd);
FavoritesConfig::instance().sync(m_items);
}
QVector foldersId;
for (const auto &folder : FavoriteFolderHelper::instance()->folderData()) {
foldersId.append(folder.getId());
if (!m_items.contains(FOLDER_ID_SCHEME + QString::number(folder.getId()))) {
m_items.insert(m_items.count(), FOLDER_ID_SCHEME + QString::number(folder.getId()));
FavoritesConfig::instance().sync(m_items);
}
}
m_folders.swap(foldersId);
}
void AppFavoritesModel::Private::onAppUpdated(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles)
{
for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
if (roles.contains(DataEntity::Favorite)) {
updateFavoritesApps(m_sourceModel->index(row, 0, QModelIndex()));
} else {
auto index = m_sourceModel->index(row, 0);
int favoriteIndex = m_items.indexOf(APP_ID_SCHEME + index.data(DataEntity::Id).toString());
Q_EMIT q->dataChanged(q->index(favoriteIndex, 0, QModelIndex()), q->index(favoriteIndex, 0, QModelIndex()), roles);
}
}
}
void AppFavoritesModel::Private::updateFavoritesApps(const QModelIndex &sourceIndex)
{
auto id = sourceIndex.data(DataEntity::Id).toString();
auto favorite = sourceIndex.data(DataEntity::Favorite).toInt();
if (id.isEmpty()) {
return;
}
QPersistentModelIndex index(sourceIndex);
if (favorite > 0 && !m_favoritesApps.contains(index)) {
addFavoriteApp(index, m_items.count());
} else if (favorite == 0) {
if (FavoriteFolderHelper::instance()->containApp(id)) {
FavoriteFolderHelper::instance()->removeAppFromFolder(id);
}
m_favoritesApps.removeOne(index);
removeFavoriteApp(index.data(DataEntity::Id).toString());
}
}
void AppFavoritesModel::Private::onAppRemoved(const QModelIndex &parent, int first, int last)
{
for (int row = first; row <= last; ++row) {
QModelIndex index = m_sourceModel->index(row, 0, {});
if (index.data(DataEntity::Favorite).toInt() > 0) {
QString appId = index.data(DataEntity::Id).toString();
if (FavoriteFolderHelper::instance()->containApp(appId)) {
FavoriteFolderHelper::instance()->removeAppFromFolder(appId);
}
QPersistentModelIndex modelIndex(index);
m_favoritesApps.removeOne(modelIndex);
removeFavoriteApp(index.data(DataEntity::Id).toString());
}
}
}
void AppFavoritesModel::Private::addFavoriteApp(const QPersistentModelIndex &modelIndex, const int &index)
{
if (!m_favoritesApps.contains(modelIndex) && modelIndex.isValid()) {
m_favoritesApps.append(modelIndex);
}
auto id = APP_ID_SCHEME + modelIndex.data(DataEntity::Id).toString();
if (!m_items.contains(id)) {
q->beginInsertRows(QModelIndex(), index, index);
m_items.insert(index, id);
q->endInsertRows();
FavoritesConfig::instance().sync(m_items);
}
}
void AppFavoritesModel::Private::removeFavoriteApp(const QString &appId)
{
int index = m_items.indexOf(APP_ID_SCHEME + appId);
if (index > -1 && index < m_items.count()) {
q->beginRemoveRows(QModelIndex(), index, index);
m_items.takeAt(index);
q->endRemoveRows();
FavoritesConfig::instance().sync(m_items);
}
}
void AppFavoritesModel::Private::onFolderAdded(const int &folderId, int order)
{
if (!m_folders.contains(folderId)) {
m_folders.append(folderId);
FavoritesFolder folder;
FavoriteFolderHelper::instance()->getFolderFromId(folderId, folder);
for (auto app : folder.getApps()) {
removeFavoriteApp(app);
}
order = std::max(0, order);
q->beginInsertRows(QModelIndex(), order, order);
m_items.insert(order, FOLDER_ID_SCHEME + QString::number(folderId));
q->endInsertRows();
FavoritesConfig::instance().sync(m_items);
} else {
qWarning() << "Favorites Add New Folder Error: " << folderId << "Already Have!";
}
}
void AppFavoritesModel::Private::onFolderDeleted(const int &folderId, const QStringList &apps)
{
if (m_folders.contains(folderId)) {
m_folders.removeOne(folderId);
int index = m_items.indexOf(FOLDER_ID_SCHEME + QString::number(folderId));
q->beginRemoveRows(QModelIndex(), index, index);
m_items.takeAt(index);
q->endRemoveRows();
FavoritesConfig::instance().sync(m_items);
for (int i = 0; i < apps.count(); i++) {
QPersistentModelIndex modelIndex(m_sourceModel->index(m_sourceModel->indexOfApp(apps.at(i)), 0));
addFavoriteApp(modelIndex, index + i);
}
} else {
qWarning() << "Favorites Remove Folder Error: " << folderId << "Does Not Exist!";
}
}
void AppFavoritesModel::Private::onFolderAppChanged(const int &folderId, const QString &appId, bool isAdded)
{
// 添加、移除应用到应用组
if (isAdded) {
removeFavoriteApp(appId);
} else {
QPersistentModelIndex modelIndex(m_sourceModel->index(m_sourceModel->indexOfApp(appId), 0));
addFavoriteApp(modelIndex);
}
int row = m_items.indexOf(FOLDER_ID_SCHEME + QString::number(folderId));
Q_EMIT q->dataChanged(q->index(row), q->index(row), QVector{DataEntity::Icon});
}
QPersistentModelIndex AppFavoritesModel::Private::getIndexFromAppId(const QString &id) const
{
auto modelIndex = std::find_if(m_favoritesApps.constBegin(), m_favoritesApps.constEnd(), [&id] (const QPersistentModelIndex &index) {
return index.data(DataEntity::Id).toString() == id;
});
if (modelIndex == m_favoritesApps.constEnd()) {
return {};
}
return *modelIndex;
}
AppFavoritesModel &AppFavoritesModel::instance()
{
static AppFavoritesModel appFavoritesModel;
return appFavoritesModel;
}
AppFavoritesModel::AppFavoritesModel(QObject *parent) : QAbstractListModel(parent), d(new Private(this))
{
d->m_sourceModel = BasicAppModel::instance();
d->init();
connect(BasicAppModel::instance(), &BasicAppModel::dataChanged, this, [&](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) {
d->onAppUpdated(topLeft, bottomRight, roles);
});
connect(BasicAppModel::instance(), &BasicAppModel::rowsAboutToBeRemoved, this, [&](const QModelIndex&parent, int first, int last) {
d->onAppRemoved(parent, first, last);
});
connect(FavoriteFolderHelper::instance(), &FavoriteFolderHelper::folderAdded, this, [&] (int folderId, int order) {
d->onFolderAdded(folderId, order);
});
connect(FavoriteFolderHelper::instance(), &FavoriteFolderHelper::folderToBeDeleted, this, [&](int folderId, const QStringList& apps) {
d->onFolderDeleted(folderId, apps);
});
connect(FavoriteFolderHelper::instance(), &FavoriteFolderHelper::folderAppChanged, this, [&] (int folderId, const QString& app, bool isAdded) {
d->onFolderAppChanged(folderId, app, isAdded);
});
connect(FavoriteFolderHelper::instance(), &FavoriteFolderHelper::folderAppsChanged, this, [&] (int folderId) {
int row = d->m_items.indexOf(FOLDER_ID_SCHEME + QString::number(folderId));
Q_EMIT dataChanged(index(row), index(row), QVector{DataEntity::Icon});
});
connect(FavoriteFolderHelper::instance(), &FavoriteFolderHelper::folderNameChanged, this, [&] (int folderId) {
int row = d->m_items.indexOf(FOLDER_ID_SCHEME + QString::number(folderId));
Q_EMIT dataChanged(index(row), index(row), QVector{DataEntity::Name});
});
}
AppFavoritesModel::~AppFavoritesModel()
{
if (d) {
delete d;
d = nullptr;
}
}
QHash AppFavoritesModel::roleNames() const
{
QHash names;
names.insert(DataEntity::Id, "id");
names.insert(DataEntity::Icon, "icon");
names.insert(DataEntity::Name, "name");
names.insert(DataEntity::Type, "type");
names.insert(DataEntity::DesktopName, "desktopName");
return names;
}
int AppFavoritesModel::rowCount(const QModelIndex &parent) const
{
return d->m_items.count();
}
QVariant AppFavoritesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= rowCount()) {
return {};
}
QString id = d->m_items.at(index.row());
// 检查并提取不同前缀后的ID
if (id.startsWith(APP_ID_SCHEME)) {
auto appModelIndex = d->getIndexFromAppId(id.mid(6));
return appModelIndex.data(role);
} else if (id.startsWith(FOLDER_ID_SCHEME)) {
return folderDataFromId(id.mid(9), role);
} else if (id.startsWith(FILE_ID_SCHEME)) {
return fileDataFromUrl(id.mid(7), role);
} else {
return {};
}
}
QVariant AppFavoritesModel::folderDataFromId(const QString &folderId, int role) const
{
FavoritesFolder folder;
if (!FavoriteFolderHelper::instance()->getFolderFromId(folderId.toInt(), folder)) {
return {};
}
switch (role) {
case DataEntity::Id:
return QString::number(folder.getId());
case DataEntity::Icon:
return FavoriteFolderHelper::folderIcon(folder);
case DataEntity::Name:
return folder.getName();
case DataEntity::Type:
return DataType::Folder;
default:
break;
}
return {};
}
QVariant AppFavoritesModel::fileDataFromUrl(const QString &url, int role) const
{
switch (role) {
case DataEntity::Id:
return url;
case DataEntity::Icon: {
QMimeDatabase mimeDatabase;
return mimeDatabase.mimeTypeForFile(url).iconName();
}
case DataEntity::Name:
return QUrl(url).fileName();
case DataEntity::Type:
return DataType::Files;
default:
break;
}
return {};
}
void AppFavoritesModel::changeFileState(const QString &url, const bool &favorite)
{
if (url.isEmpty()) {
return;
}
QString fileId;
if (url.startsWith(FILE_ID_SCHEME)) {
fileId = url;
} else {
fileId = FILE_ID_SCHEME + url;
}
if (favorite) {
d->m_favoritesFiles.append(fileId);
d->m_items.append(fileId);
FavoritesConfig::instance().sync(d->m_items);
} else {
d->m_favoritesFiles.removeAll(fileId);
d->m_items.removeAll(fileId);
FavoritesConfig::instance().sync(d->m_items);
}
}
int AppFavoritesModel::getOrderById(const QString& id)
{
return d->m_items.indexOf(id);
}
void AppFavoritesModel::openMenu(const int& row)
{
if (row < 0 || row >= rowCount()) {
return;
}
if (data(index(row, 0), DataEntity::Type).value() == UkuiMenu::DataType::Normal) {
ContextMenuManager::instance()->showMenu(data(index(row, 0), DataEntity::Entity).value(), MenuInfo::Extension, "favorite");
} else {
DataEntity appData;
appData.setId(data(index(row, 0), DataEntity::Id).toString());
appData.setFavorite(data(index(row, 0), DataEntity::Favorite).toInt());
appData.setType(data(index(row, 0), DataEntity::Type).value());
ContextMenuManager::instance()->showMenu(appData, MenuInfo::Extension, "favorite");
}
}
void AppFavoritesModel::addAppToFavorites(const QString &id, int index)
{
if (d->getIndexFromAppId(id).isValid() || FavoriteFolderHelper::instance()->containApp(id)) {
qWarning() << "This application is already included in the favorite apps!";
return;
}
if (index == -1) {
index = rowCount();
}
QPersistentModelIndex modelIndex(d->m_sourceModel->index(d->m_sourceModel->indexOfApp(id), 0));
d->addFavoriteApp(modelIndex, index);
d->m_sourceModel->databaseInterface()->fixAppToFavorite(id, 1);
}
void AppFavoritesModel::removeAppFromFavorites(const QString &id)
{
if (id.isEmpty()) {
return;
}
d->removeFavoriteApp(id);
d->m_sourceModel->databaseInterface()->fixAppToFavorite(id, 0);
}
void AppFavoritesModel::exchangedAppsOrder(int indexFrom, int indexTo)
{
indexFrom = qMin(indexFrom, d->m_items.size() -1);
indexTo = qMin(indexTo, d->m_items.size() -1);
if (indexFrom == indexTo || indexFrom < 0 || indexTo < 0) {
return;
}
if (indexFrom < indexTo) {
beginMoveRows(QModelIndex(), indexFrom, indexFrom, QModelIndex(), indexTo + 1);
} else {
beginMoveRows(QModelIndex(), indexFrom, indexFrom, QModelIndex(), indexTo);
}
d->m_items.move(indexFrom, indexTo);
endMoveRows();
FavoritesConfig::instance().sync(d->m_items);
}
void AppFavoritesModel::addAppsToNewFolder(const QString& idFrom, const QString& idTo)
{
if (idFrom == idTo) {
return;
}
if (d->getIndexFromAppId(idFrom).isValid() && d->getIndexFromAppId(idTo).isValid()) {
FavoriteFolderHelper::instance()->addAppsToNewFolder(idFrom, idTo, "");
}
}
void AppFavoritesModel::addAppToFolder(const QString& appId, const QString& folderId)
{
if (folderId == "") {
FavoriteFolderHelper::instance()->addAppToNewFolder(appId, "");
return;
}
FavoriteFolderHelper::instance()->addAppToFolder(appId, folderId.toInt());
}
void AppFavoritesModel::clearFavorites()
{
// 先处理所有应用组中的应用,从应用组中移除
QSet allFolderApps;
for (const auto &folder : FavoriteFolderHelper::instance()->folderData()) {
for (const auto &appId : folder.getApps()) {
allFolderApps.insert(appId);
}
}
for (const auto &appId : allFolderApps) {
FavoriteFolderHelper::instance()->removeAppFromFolder(appId);
}
// 再处理独立应用(此时包含从应用组移出的应用)
auto favApps = d->m_favoritesApps;
for (const auto &appIndex : favApps) {
QString id = appIndex.data(DataEntity::Id).toString();
removeAppFromFavorites(id);
}
d->m_favoritesFiles.clear();
}
QString AppFavoritesModel::getDesktopFile(const QString& dragSourceUrl)
{
QUrl url = QUrl(dragSourceUrl);
return url.isValid() ? url.path() : "";
}
} // UkuiMenu
#include "moc_app-favorite-model.cpp"
ukui-menu/src/extension/favorite/favorite-extension-plugin.h 0000664 0001750 0001750 00000002164 15160463353 023350 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_FAVORITE_EXTENSION_PLUGIN_H
#define UKUI_MENU_FAVORITE_EXTENSION_PLUGIN_H
#include "../menu-extension-plugin.h"
namespace UkuiMenu {
class FavoriteExtensionPlugin : public MenuExtensionPlugin
{
public:
QString id() override;
WidgetExtension *createWidgetExtension() override;
ContextMenuExtension *createContextMenuExtension() override;
};
} // UkuiMenu
#endif //UKUI_MENU_FAVORITE_EXTENSION_PLUGIN_H
ukui-menu/src/extension/favorite/favorite-folder-helper.h 0000664 0001750 0001750 00000006413 15160463365 022574 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_FAVORITE_FOLDER_HELPER_H
#define UKUI_MENU_FAVORITE_FOLDER_HELPER_H
#include
#include
#include
#include
#include
#include
namespace UkuiMenu {
#define FOLDER_MAX_ICON_NUM 16
class FavoriteFolderHelper;
class FavoritesFolder
{
Q_GADGET
Q_PROPERTY(int id READ getId WRITE setId)
Q_PROPERTY(QString name READ getName)
Q_PROPERTY(QStringList apps READ getApps)
friend class FavoriteFolderHelper;
public:
void setId(int folderId) {id = folderId;}
int getId() const { return id; }
QString getName() const { return name; }
QStringList getApps() const { return apps; }
QStringList getDisplayApps() const;
private:
int id; // 文件夹唯一Id,文件夹排序值
QString name; // 名称
QStringList apps; // 应用列表
};
class FavoriteFolderHelper : public QObject
{
Q_OBJECT
public:
static FavoriteFolderHelper *instance();
static QVariantList folderIcon(const FavoritesFolder &folder);
~FavoriteFolderHelper() override;
bool getFolderFromId(const int& folderId, FavoritesFolder& folder);
bool containsFolder(const int& folderId);
bool containApp(const QString& appId);
bool deleteFolder(const int& folderId);
QList folderData();
void addAppToFolder(const QString& appId, const int& folderId);
void addAppToNewFolder(const QString& appId, const QString& folderName);
void addAppsToNewFolder(const QString& idFrom, const QString& idTo, const QString& folderName);
void removeAppFromFolder(const QString& appId);
void renameFolder(const int& folderId, const QString& folderName);
void exchangedOrder(const int &indexFrom, const int &indexTo, const int& folderId);
void forceSync();
QStringList appsInFolders();
Q_SIGNALS:
void folderAppsChanged(int folderId); // 应用组内部顺序改变
void folderNameChanged(int folderId); // 应用组名称改变
void folderAdded(int folderId, const int& order); // 添加应用组
void folderToBeDeleted(int folderId, const QStringList& apps); // 解散应用组
void folderAppChanged(int folderId, const QString& app, bool isAdded = true); // 应用组内app添加、删除
private:
FavoriteFolderHelper();
void readData();
void saveData();
void insertFolder(const FavoritesFolder& folder);
// TODO 配置文件监听
private:
QMutex m_mutex;
//TODO 指针
QMap m_folders;
static QString s_folderConfigFile;
};
} // UkuiMenu
#endif //UKUI_MENU_FAVORITE_FOLDER_HELPER_H
ukui-menu/src/extension/favorite/favorite-context-menu.h 0000664 0001750 0001750 00000002625 15160463353 022470 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_FAVORITE_CONTEXT_MENU_H
#define UKUI_MENU_FAVORITE_CONTEXT_MENU_H
#include "../context-menu-extension.h"
namespace UkuiMenu {
class FavoriteContextMenu : public ContextMenuExtension
{
public:
int index() const override;
QList actions(const DataEntity &data, QMenu *parent,
const MenuInfo::Location &location,
const QString &locationId) override;
private:
void appendActionsForAppsInFolder(QObject *parent, const QString &appId, QList &list);
void appendActionsForAppsOutsideFolder(QObject *parent, const QString &appId, QList &list);
};
} // UkuiMenu
#endif //UKUI_MENU_FAVORITE_CONTEXT_MENU_H
ukui-menu/src/extension/favorite/favorite-filter-model.h 0000664 0001750 0001750 00000003753 15160463353 022430 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: youdiansaodongxi
*
*/
#ifndef FAVORITEFILTERMODEL_H
#define FAVORITEFILTERMODEL_H
#include
namespace UkuiMenu {
class AppFavoritesModel;
class FavoriteFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
static FavoriteFilterModel *instance();
QVariant data(const QModelIndex &index, int role) const override;
Q_INVOKABLE void openMenu(const int &row);
Q_INVOKABLE void addAppToFavorites(const QString &id, int index = -1);
Q_INVOKABLE void removeAppFromFavorites(const QString &id);
Q_INVOKABLE void exchangedAppsOrder(int indexFrom, int indexTo);
Q_INVOKABLE void addAppsToNewFolder(const QString &idFrom, const QString &idTo);
Q_INVOKABLE void addAppToFolder(const QString &appId, const QString& folderId);
Q_INVOKABLE void clearFavorites();
Q_INVOKABLE QString getDesktopFile(const QString &dragSourceUrl);
Q_INVOKABLE void addAppFromFolder(const QString& appId, int order = -1);
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
private Q_SLOTS:
void onSecurityControlChanged();
private:
FavoriteFilterModel(QObject *parent = nullptr);
AppFavoritesModel *m_sourceModel = nullptr;
};
} // UkuiMenu
#endif // FAVORITEFILTERMODEL_H
ukui-menu/src/extension/favorite/favorites-config.h 0000664 0001750 0001750 00000002666 15160463353 021477 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_FAVORITES_CONFIG_H
#define UKUI_MENU_FAVORITES_CONFIG_H
#include
#include
#include
static const QString APP_ID_SCHEME = "app://";
static const QString FILE_ID_SCHEME = "file://";
static const QString FOLDER_ID_SCHEME = "folder://";
namespace UkuiMenu {
class FavoritesConfig : public QObject
{
Q_OBJECT
public:
static FavoritesConfig &instance();
void sync(const QStringList &list);
QStringList getConfig();
private:
explicit FavoritesConfig(QObject *parent = nullptr);
void initConfig();
QStringList updateInvalidUrlList(QStringList &list);
static QString s_favoritesConfigFile;
QStringList m_configList;
};
} // UkuiMenu
#endif //UKUI_MENU_FAVORITES_CONFIG_H
ukui-menu/src/extension/favorite/favorite-context-menu.cpp 0000664 0001750 0001750 00000012161 15160463365 023022 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "favorite-context-menu.h"
#include "app-favorite-model.h"
#include "event-track.h"
#include "basic-app-model.h"
#include "favorite-folder-helper.h"
namespace UkuiMenu {
int FavoriteContextMenu::index() const
{
return 512;
}
QList
FavoriteContextMenu::actions(const DataEntity &data, QMenu *parent, const MenuInfo::Location &location,
const QString &locationId)
{
if (!parent) {
return {};
}
QList list;
if (data.type() == DataType::Folder) {
list << new QAction(QIcon::fromTheme("app-group-disband-symbolic"), QObject::tr("Dissolve folder"), parent);
QObject::connect(list.last(), &QAction::triggered, parent, [data] {
FavoriteFolderHelper::instance()->deleteFolder(data.id().toInt());
});
return list;
}
switch (location) {
case MenuInfo::AppList:
case MenuInfo::FullScreen:
case MenuInfo::FolderPage: {
if (data.favorite() == 0) {
list << new QAction(QIcon::fromTheme("non-starred-symbolic"), QObject::tr("Add to favorite"), parent);
QObject::connect(list.last(), &QAction::triggered, parent, [data] {
AppFavoritesModel::instance().addAppToFavorites(data.id());
BasicAppModel::instance()->databaseInterface()->updateApLaunchedState(data.id(), true);
//BasicAppModel::instance()->databaseInterface()->fixAppToFavorite(data.id(), 1);
EventTrack::instance()->sendDefaultEvent("fix_to_favorite", "Right-click Menu");
});
} else if (data.favorite() > 0) {
list << new QAction(QIcon::fromTheme("ukui-cancel-star-symbolic"), QObject::tr("Remove from favorite"), parent);
QObject::connect(list.last(), &QAction::triggered, parent, [data] {
AppFavoritesModel::instance().removeAppFromFavorites(data.id());
BasicAppModel::instance()->databaseInterface()->fixAppToFavorite(data.id(), 0);
EventTrack::instance()->sendDefaultEvent("remove_from_favorite", "Right-click Menu");
});
}
break;
}
case MenuInfo::Extension: {
appendActionsForAppsOutsideFolder(parent, data.id(), list);
QAction *action = new QAction(QIcon::fromTheme("ukui-cancel-star-symbolic"), QObject::tr("Remove from favorite"), parent);
QObject::connect(action, &QAction::triggered, parent, [data] {
AppFavoritesModel::instance().removeAppFromFavorites(data.id());
EventTrack::instance()->sendDefaultEvent("remove_from_favorite", "Right-click Menu");
});
list << action;
break;
}
case MenuInfo::Folder: {
appendActionsForAppsInFolder(parent, data.id(), list);
break;
}
default:
break;
}
return list;
}
void FavoriteContextMenu::appendActionsForAppsInFolder(QObject *parent, const QString &appId, QList &list)
{
FavoritesFolder folder;
list << new QAction(QIcon::fromTheme("app-group-moveout-symbolic"), QObject::tr("Remove from folder"), parent);
QObject::connect(list.last(), &QAction::triggered, parent, [appId] {
FavoriteFolderHelper::instance()->removeAppFromFolder(appId);
});
}
void FavoriteContextMenu::appendActionsForAppsOutsideFolder(QObject *parent, const QString &appId, QList &list)
{
QAction *action = new QAction(QIcon::fromTheme("app-group-movein-symbolic"), QObject::tr("Move to folder"), parent);
QMenu *subMenu = new QMenu();
QAction *subAction = new QAction(QObject::tr("Create a new folder"), parent);
QObject::connect(subAction, &QAction::triggered, parent, [appId] {
AppFavoritesModel::instance().addAppToFolder(appId, "");
});
subMenu->addAction(subAction);
for (auto folder : FavoriteFolderHelper::instance()->folderData()) {
QString folderName = folder.getName();
int folderId = folder.getId();
QAction *subAction = new QAction(QObject::tr("Add to \"%1\"").arg(folderName), parent);
QObject::connect(subAction, &QAction::triggered, parent, [appId, folderId] {
AppFavoritesModel::instance().addAppToFolder(appId, QString::number(folderId));
});
subMenu->addAction(subAction);
}
action->setMenu(subMenu);
list << action;
}
} // UkuiMenu
ukui-menu/src/extension/favorite/favorite-filter-model.cpp 0000664 0001750 0001750 00000007532 15160463365 022765 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: youdiansaodongxi
*
*/
#include "favorite-filter-model.h"
#include "app-favorite-model.h"
#include "favorites-config.h"
#include "security-function-control.h"
#include "favorite-folder-helper.h"
#include
namespace UkuiMenu {
FavoriteFilterModel *FavoriteFilterModel::instance()
{
static FavoriteFilterModel model;
return &model;
}
QVariant FavoriteFilterModel::data(const QModelIndex &index, int role) const
{
return sourceModel()->data(mapToSource(index), role);
}
void FavoriteFilterModel::openMenu(const int &row)
{
m_sourceModel->openMenu(mapToSource(this->index(row, 0)).row());
}
void FavoriteFilterModel::addAppToFavorites(const QString &id, int index)
{
if (index != -1) {
index = mapToSource(this->index(index, 0)).row();
}
m_sourceModel->addAppToFavorites(id, index);
}
void FavoriteFilterModel::removeAppFromFavorites(const QString &id)
{
m_sourceModel->removeAppFromFavorites(id);
}
void FavoriteFilterModel::exchangedAppsOrder(int indexFrom, int indexTo)
{
indexFrom = mapToSource(this->index(indexFrom, 0)).row();
indexTo = mapToSource(this->index(indexTo, 0)).row();
m_sourceModel->exchangedAppsOrder(indexFrom, indexTo);
}
void FavoriteFilterModel::addAppsToNewFolder(const QString &idFrom, const QString &idTo)
{
m_sourceModel->addAppsToNewFolder(idFrom, idTo);
}
void FavoriteFilterModel::addAppToFolder(const QString &appId, const QString &folderId)
{
m_sourceModel->addAppToFolder(appId, folderId);
}
void FavoriteFilterModel::clearFavorites()
{
m_sourceModel->clearFavorites();
}
QString FavoriteFilterModel::getDesktopFile(const QString &dragSourceUrl)
{
return m_sourceModel->getDesktopFile(dragSourceUrl);
}
void FavoriteFilterModel::addAppFromFolder(const QString& appId, int order)
{
FavoriteFolderHelper::instance()->removeAppFromFolder(appId);
order = qBound(0, order, m_sourceModel->rowCount() - 1);
exchangedAppsOrder(0, order);
}
bool FavoriteFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent);
if (sourceIndex.data(DataEntity::Type) == DataType::Folder) {
FavoritesFolder folder;
FavoriteFolderHelper::instance()->getFolderFromId(sourceIndex.data(DataEntity::Id).toInt(), folder);
return !folder.getDisplayApps().isEmpty();
}
return SecurityFunctionControl::instance()->canAppDisplay(sourceIndex.data(DataEntity::Id).toString());
}
void FavoriteFilterModel::onSecurityControlChanged()
{
invalidateFilter();
dataChanged(index(0,0), index(rowCount() - 1, 0), {DataEntity::Icon});
}
FavoriteFilterModel::FavoriteFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
{
setSourceModel(&AppFavoritesModel::instance());
m_sourceModel = &AppFavoritesModel::instance();
connect(SecurityFunctionControl::instance(), &SecurityFunctionControl::appWhiteListChanged, this, &FavoriteFilterModel::onSecurityControlChanged);
connect(SecurityFunctionControl::instance(), &SecurityFunctionControl::appBlackListChanged, this, &FavoriteFilterModel::onSecurityControlChanged);
}
} // UkuiMenu
ukui-menu/src/extension/favorite/favorite-widget.cpp 0000664 0001750 0001750 00000003624 15160463353 021660 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "favorite-widget.h"
#include "favorite-filter-model.h"
namespace UkuiMenu {
FavoriteWidget::FavoriteWidget(QObject *parent) : WidgetExtension(parent)
{
m_metadata.insert(WidgetMetadata::Id, "favorite");
m_metadata.insert(WidgetMetadata::Icon, "non-starred-symbolic");
m_metadata.insert(WidgetMetadata::Name, tr("Favorite"));
m_metadata.insert(WidgetMetadata::Tooltip, tr("favorite"));
m_metadata.insert(WidgetMetadata::Version, "1.0.0");
m_metadata.insert(WidgetMetadata::Description, "favorite");
m_metadata.insert(WidgetMetadata::Main, "qrc:///qml/extensions/FavoriteExtension.qml");
m_metadata.insert(WidgetMetadata::Type, WidgetMetadata::Widget);
m_metadata.insert(WidgetMetadata::Flag, WidgetMetadata::Normal);
m_data.insert("favoriteAppsModel", QVariant::fromValue(FavoriteFilterModel::instance()));
m_data.insert("folderModel", QVariant::fromValue(&FolderModel::instance()));
}
int FavoriteWidget::index() const
{
return 0;
}
MetadataMap FavoriteWidget::metadata() const
{
return m_metadata;
}
QVariantMap FavoriteWidget::data()
{
return m_data;
}
void FavoriteWidget::receive(const QVariantMap &data)
{
WidgetExtension::receive(data);
}
} // UkuiMenu
ukui-menu/src/extension/favorite/favorite-extension-plugin.cpp 0000664 0001750 0001750 00000002151 15160463353 023677 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "favorite-extension-plugin.h"
#include "favorite-widget.h"
#include "favorite-context-menu.h"
namespace UkuiMenu {
QString FavoriteExtensionPlugin::id()
{
return "favorite";
}
WidgetExtension *FavoriteExtensionPlugin::createWidgetExtension()
{
return new FavoriteWidget;
}
ContextMenuExtension *FavoriteExtensionPlugin::createContextMenuExtension()
{
return new FavoriteContextMenu;
}
} // UkuiMenu
ukui-menu/src/extension/favorite/folder-model.cpp 0000664 0001750 0001750 00000007366 15160463365 021143 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "folder-model.h"
#include "app-folder-helper.h"
#include "app-data-manager.h"
#include "favorite/favorite-folder-helper.h"
#include "context-menu-manager.h"
#include "libappdata/basic-app-model.h"
#include "security-function-control.h"
namespace UkuiMenu {
FolderModel::FolderModel(QObject *parent) : QAbstractListModel(parent)
{
connect(FavoriteFolderHelper::instance(), &FavoriteFolderHelper::folderAppsChanged, this, &FolderModel::loadFolderData);
connect(FavoriteFolderHelper::instance(), &FavoriteFolderHelper::folderAppChanged, this, &FolderModel::loadFolderData);
connect(FavoriteFolderHelper::instance(), &FavoriteFolderHelper::folderToBeDeleted, this, [this] (int id) {
if (id == m_folderId) {
beginResetModel();
m_folderId = -1;
m_apps.clear();
endResetModel();
}
});
connect(SecurityFunctionControl::instance(), &SecurityFunctionControl::appWhiteListChanged, [this] {
loadFolderData(m_folderId);
});
connect(SecurityFunctionControl::instance(), &SecurityFunctionControl::appBlackListChanged, [this] {
loadFolderData(m_folderId);
});
}
void FolderModel::setFolderId(const QString &folderId)
{
bool ok;
int id = folderId.toInt(&ok);
if (!ok) {
return;
}
loadFolderData(id);
}
void FolderModel::renameFolder(const QString &folderName)
{
FavoriteFolderHelper::instance()->renameFolder(m_folderId, folderName);
}
void FolderModel::exchangedOrder(const int& indexFrom, const int& indexTo)
{
FavoriteFolderHelper::instance()->exchangedOrder(indexFrom, indexTo, m_folderId);
}
void FolderModel::loadFolderData(int id)
{
FavoritesFolder folder;
if (!FavoriteFolderHelper::instance()->getFolderFromId(id, folder)) {
return;
}
beginResetModel();
m_folderId = id;
m_apps = folder.getDisplayApps();
endResetModel();
Q_EMIT countChanged();
}
int FolderModel::rowCount(const QModelIndex &parent) const
{
return m_apps.count();
}
QVariant FolderModel::data(const QModelIndex &index, int role) const
{
int i = index.row();
if (i < 0 || i >= m_apps.size()) {
return {};
}
DataEntity app;
if (!BasicAppModel::instance()->getAppById(m_apps.at(i), app)) {
return {};
}
switch (role) {
case DataEntity::Id:
return app.id();
case DataEntity::Type:
return app.type();
case DataEntity::Icon:
return app.icon();
case DataEntity::Name:
return app.name();
case DataEntity::Comment:
return app.comment();
case DataEntity::ExtraData:
return app.extraData();
case DataEntity::DesktopName:
return app.desktopName();
default:
break;
}
return {};
}
QHash FolderModel::roleNames() const
{
return DataEntity::AppRoleNames();
}
int FolderModel::count()
{
return m_apps.count();
}
FolderModel &FolderModel::instance()
{
static FolderModel folderModel;
return folderModel;
}
} // UkuiMenu
ukui-menu/src/extension/favorite/favorites-config.cpp 0000664 0001750 0001750 00000011456 15160463353 022027 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include
#include
#include
#include "favorites-config.h"
#include "basic-app-model.h"
#include "favorite-folder-helper.h"
#define FOLDER_FILE_PATH ".config/ukui-menu/"
#define FOLDER_FILE_NAME "favorite.json"
namespace UkuiMenu {
QString FavoritesConfig::s_favoritesConfigFile = QDir::homePath() + "/" + FOLDER_FILE_PATH + FOLDER_FILE_NAME;
/**
* 添加版本号,区分旧文件内容
*/
static const QString FAVORITE_CONFIG_VERSION = QStringLiteral("1.0.0");
FavoritesConfig &FavoritesConfig::instance()
{
static FavoritesConfig favoritesConfig;
return favoritesConfig;
}
FavoritesConfig::FavoritesConfig(QObject *parent)
{
initConfig();
}
void FavoritesConfig::sync(const QStringList &list)
{
if (m_configList == list) {
return;
}
m_configList = list;
QDir dir;
QString folderConfigDir(QDir::homePath() + "/" + FOLDER_FILE_PATH);
if (!dir.exists(folderConfigDir)) {
if (!dir.mkdir(folderConfigDir)) {
qWarning() << "FavoritesConfig::Unable to create configuration file.";
return;
}
}
QFile file(s_favoritesConfigFile);
file.open(QFile::WriteOnly);
QJsonDocument jsonDocument;
QJsonObject fileObject;
fileObject.insert("version", FAVORITE_CONFIG_VERSION);
fileObject.insert("favorites", QJsonArray::fromStringList(m_configList));
jsonDocument.setObject(fileObject);
if (file.write(jsonDocument.toJson()) == -1) {
qWarning() << "FavoritesConfig::Error saving configuration file.";
}
file.flush();
file.close();
}
QStringList FavoritesConfig::getConfig()
{
return m_configList;
}
void FavoritesConfig::initConfig()
{
QFile file(s_favoritesConfigFile);
if (!file.open(QFile::ReadOnly)) {
qWarning() << "FavoritesConfig: configuration files open failed.";
return;
}
QJsonDocument jsonDocument(QJsonDocument::fromJson(file.readAll()));
file.close();
if (jsonDocument.isNull() || jsonDocument.isEmpty()) {
qWarning() << "FavoritesConfig: configuration files format is empty.";
return;
}
// 配置文件补充添加版本号1.0.0
QStringList list, invalidUrl;
if (jsonDocument.isObject()) {
QJsonObject fileObject = jsonDocument.object();
if (fileObject.value("version").toString() == FAVORITE_CONFIG_VERSION && fileObject.contains("favorites")) {
for (const QVariant &variant : fileObject.value(QLatin1String("favorites")).toArray().toVariantList()) {
list << variant.toString();
}
invalidUrl = updateInvalidUrlList(list);
if (invalidUrl.isEmpty()) {
m_configList = list;
} else {
for (const QString &id : invalidUrl) {
list.removeAll(id);
}
sync(list);
}
}
} else if (jsonDocument.isArray()) {
for (const QVariant &variant : jsonDocument.array().toVariantList()) {
list << variant.toString();
}
invalidUrl = updateInvalidUrlList(list);
if (!invalidUrl.isEmpty()) {
for (const QString&id : invalidUrl) {
list.removeAll(id);
}
}
sync(list);
} else {
qWarning() << "FavoritesConfig: configuration files format is incorrect.";
}
}
QStringList FavoritesConfig::updateInvalidUrlList(QStringList &list)
{
QStringList invalidUrl;
for (auto &url : list) {
if (url.startsWith(APP_ID_SCHEME)) {
QString appId = url.mid(6);
if (FavoriteFolderHelper::instance()->containApp(appId) || appId.isEmpty() || (
BasicAppModel::instance()->indexOfApp(appId) < 0)) {
invalidUrl.append(url);
}
} else if (url.startsWith(FOLDER_ID_SCHEME)) {
bool ok;
int folderId = url.mid(9).toInt(&ok);
if (!ok || !FavoriteFolderHelper::instance()->containsFolder(folderId)) {
invalidUrl.append(url);
}
}
}
return invalidUrl;
}
} // UkuiMenu
ukui-menu/src/extension/favorite/folder-model.h 0000664 0001750 0001750 00000003174 15160463365 020601 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_FOLDER_MODEL_H
#define UKUI_MENU_FOLDER_MODEL_H
#include
#include "commons.h"
namespace UkuiMenu {
class FolderModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
static FolderModel &instance();
Q_INVOKABLE void setFolderId(const QString &folderId);
Q_INVOKABLE void renameFolder(const QString &folderName);
Q_INVOKABLE void exchangedOrder(const int &indexFrom, const int &indexTo);
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash roleNames() const override;
int count();
Q_SIGNALS:
void countChanged();
private Q_SLOTS:
void loadFolderData(int id);
private:
explicit FolderModel(QObject *parent = nullptr);
int m_folderId;
QStringList m_apps;
};
} // UkuiMenu
#endif //UKUI_MENU_FOLDER_MODEL_H
ukui-menu/src/extension/favorite/app-favorite-model.h 0000664 0001750 0001750 00000005537 15160463353 021725 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_APP_FAVORITE_MODEL_H
#define UKUI_MENU_APP_FAVORITE_MODEL_H
#include "data-entity.h"
#include "libappdata/basic-app-model.h"
#include
#include
namespace UkuiMenu {
class AppFavoritesModel : public QAbstractListModel
{
Q_OBJECT
public:
static AppFavoritesModel &instance();
~AppFavoritesModel() override;
QHash roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
void changeFileState(const QString &url, const bool &favorite); //TODO
int getOrderById(const QString&id);
void openMenu(const int &row);
/**
* 通过id添加应用到收藏
* @param id
* @param index 默认为-1,添加到收藏最后一位;可以添加到收藏指定位置
*/
void addAppToFavorites(const QString &id, int index = -1);
/**
* 通过id从收藏中移除
* @param id
*/
void removeAppFromFavorites(const QString &id);
/**
* 拖拽交换位置。
* @param indexFrom
* @param indexTo
*/
void exchangedAppsOrder(int indexFrom, int indexTo);
/**
* 两个应用推拽合并为应用组。
* @param idFrom
* @param idTo 拖拽至某一应用,并在该位置创建应用组
*/
void addAppsToNewFolder(const QString &idFrom, const QString &idTo);
/**
* 添加应用到应用组,包括新建应用组。
* @param appId
* @param folderId id为""时,新建应用组;id为数值时,添加至对应应用组
*/
void addAppToFolder(const QString &appId, const QString& folderId);
/**
* 清空所有已收藏应用
*/
void clearFavorites();
/**
* 通过url获取对应的应用名称
**/
QString getDesktopFile(const QString &dragSourceUrl);
private:
explicit AppFavoritesModel(QObject* parent = nullptr);
QVariant folderDataFromId(const QString &id, int role) const;
QVariant fileDataFromUrl(const QString &url, int role) const;
class Private;
Private *d = nullptr;
};
} // UkuiMenu
#endif //UKUI_MENU_APP_FAVORITE_MODEL_H
ukui-menu/src/extension/favorite/favorite-folder-helper.cpp 0000664 0001750 0001750 00000026221 15160463365 023126 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include
#include
#include
#include
#include
#include "favorite-folder-helper.h"
#include "app-favorite-model.h"
#include "event-track.h"
#include "favorites-config.h"
#include "libappdata/basic-app-model.h"
#include "security-function-control.h"
#define FOLDER_FILE_PATH ".config/ukui-menu/"
#define FOLDER_FILE_NAME "folder.json"
namespace UkuiMenu {
QString FavoriteFolderHelper::s_folderConfigFile = QDir::homePath() + "/" + FOLDER_FILE_PATH + FOLDER_FILE_NAME;
/**
* changelog 1.0.0 添加版本号,区分旧文件内容
*/
static const QString FOLDER_CONFIG_VERSION = QStringLiteral("1.0.0");
FavoriteFolderHelper *FavoriteFolderHelper::instance()
{
static FavoriteFolderHelper FavoriteFolderHelper;
return &FavoriteFolderHelper;
}
FavoriteFolderHelper::FavoriteFolderHelper()
{
qRegisterMetaType("FavoritesFolder");
if (!QFile::exists(s_folderConfigFile)) {
QDir dir;
QString folderConfigDir(QDir::homePath() + "/" + FOLDER_FILE_PATH);
if (!dir.exists(folderConfigDir)) {
if (!dir.mkdir(folderConfigDir)) {
qWarning() << "Unable to create profile folder.";
return;
}
}
QFile file(s_folderConfigFile);
file.open(QFile::WriteOnly);
file.close();
}
readData();
}
FavoriteFolderHelper::~FavoriteFolderHelper()
{
saveData();
}
void FavoriteFolderHelper::insertFolder(const FavoritesFolder &folder)
{
QMutexLocker locker(&m_mutex);
m_folders.insert(folder.id, folder);
}
void FavoriteFolderHelper::addAppToFolder(const QString &appId, const int &folderId)
{
if (appId.isEmpty()) {
return;
}
{
QMutexLocker locker(&m_mutex);
if (!m_folders.contains(folderId)) {
return;
}
FavoritesFolder &folder = m_folders[folderId];
if (folder.apps.contains(appId)) {
return;
}
folder.apps.append(appId);
}
forceSync();
Q_EMIT folderAppChanged(folderId, appId, true);
EventTrack::instance()->sendDefaultEvent("add_app_to_folder", "AppView");
}
void FavoriteFolderHelper::addAppToNewFolder(const QString &appId, const QString &folderName)
{
if (appId.isEmpty()) {
return;
}
// TODO: max越界处理
int max = m_folders.isEmpty() ? -1 : m_folders.lastKey();
QString name = folderName;
if (name.isEmpty()) {
name = tr("New Folder %1").arg(m_folders.size() + 1);
}
FavoritesFolder folder;
folder.id = ++max;
folder.name = name;
folder.apps.append(appId);
insertFolder(folder);
forceSync();
Q_EMIT folderAdded(folder.id, AppFavoritesModel::instance().getOrderById(APP_ID_SCHEME + appId));
EventTrack::instance()->sendDefaultEvent("add_app_to_new_folder", "AppView");
}
void FavoriteFolderHelper::addAppsToNewFolder(const QString &idFrom, const QString &idTo, const QString &folderName)
{
if (idFrom.isEmpty() || idTo.isEmpty()) {
return;
}
// TODO: max越界处理
int max = m_folders.isEmpty() ? -1 : m_folders.lastKey();
QString name = folderName;
if (name.isEmpty()) {
name = tr("New Folder %1").arg(m_folders.size() + 1);
}
FavoritesFolder folder;
folder.id = ++max;
folder.name = name;
folder.apps.append(idFrom);
folder.apps.append(idTo);
insertFolder(folder);
// 确定folder位置
int orderTo = AppFavoritesModel::instance().getOrderById(APP_ID_SCHEME + idTo);
int orderFrom = AppFavoritesModel::instance().getOrderById(APP_ID_SCHEME + idFrom);
int folderOrder;
if (orderFrom > orderTo) {
folderOrder = orderTo;
} else {
folderOrder = orderTo - 1;
}
Q_EMIT folderAdded(folder.id, folderOrder);
forceSync();
}
void FavoriteFolderHelper::removeAppFromFolder(const QString& appId)
{
if (appId.isEmpty()) {
return;
}
int folderId;
{
QMutexLocker locker(&m_mutex);
for (const auto &folder: m_folders) {
if (folder.apps.contains(appId)) {
folderId = folder.getId();
}
}
if (!m_folders.contains(folderId)) {
return;
}
FavoritesFolder &folder = m_folders[folderId];
if (!folder.apps.contains(appId)) {
return;
}
folder.apps.removeOne(appId);
}
if (m_folders[folderId].getApps().isEmpty()) {
deleteFolder(folderId);
}
forceSync();
Q_EMIT folderAppChanged(folderId, appId, false);
}
bool FavoriteFolderHelper::deleteFolder(const int& folderId)
{
Q_EMIT folderToBeDeleted(folderId, m_folders[folderId].getApps());
{
QMutexLocker locker(&m_mutex);
if (!m_folders.contains(folderId)) {
return false;
}
if (!m_folders.remove(folderId)) {
return false;
}
}
forceSync();
EventTrack::instance()->sendDefaultEvent("delete_folder", "AppView");
return true;
}
void FavoriteFolderHelper::renameFolder(const int &folderId, const QString &folderName)
{
{
QMutexLocker locker(&m_mutex);
if (!m_folders.contains(folderId)) {
return;
}
if (m_folders[folderId].name == folderName) {
return;
}
m_folders[folderId].name = folderName;
}
Q_EMIT folderNameChanged(folderId);
forceSync();
}
void FavoriteFolderHelper::exchangedOrder(const int& indexFrom, const int& indexTo, const int& folderId)
{
if (indexFrom == indexTo) {
return;
}
{
QMutexLocker locker(&m_mutex);
if (!m_folders.contains(folderId)) {
return;
}
FavoritesFolder &folder = m_folders[folderId];
folder.apps.move(indexFrom, indexTo);
}
Q_EMIT folderAppsChanged(folderId);
forceSync();
}
QList FavoriteFolderHelper::folderData()
{
QMutexLocker locker(&m_mutex);
return m_folders.values();
}
bool FavoriteFolderHelper::getFolderFromId(const int &folderId, FavoritesFolder& folder)
{
QMutexLocker locker(&m_mutex);
if (!m_folders.contains(folderId)) {
return false;
}
const FavoritesFolder &tmp = m_folders[folderId];
folder = tmp;
return true;
}
bool FavoriteFolderHelper::containsFolder(const int& folderId)
{
QMutexLocker locker(&m_mutex);
return m_folders.contains(folderId);
}
bool FavoriteFolderHelper::containApp(const QString &appId)
{
QMutexLocker locker(&m_mutex);
return std::any_of(m_folders.constBegin(), m_folders.constEnd(), [appId] (const FavoritesFolder &folder) {
return folder.apps.contains(appId);
});
}
void FavoriteFolderHelper::forceSync()
{
saveData();
}
void FavoriteFolderHelper::readData()
{
QFile file(s_folderConfigFile);
if (!file.open(QFile::ReadOnly)) {
return;
}
// 读取json数据
QTextStream stream(&file);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
stream.setCodec("UTF-8");
#else
stream.setEncoding(QStringConverter::Utf8);
#endif
QString str = stream.readAll();
file.close();
QJsonParseError jsonError;
QJsonDocument jsonDocument(QJsonDocument::fromJson(str.toUtf8(),&jsonError));
if (jsonDocument.isNull() || jsonDocument.isEmpty()) {
qWarning() << "FavoriteFolderHelper: Incorrect configuration files are ignored." << jsonError.error;
return;
}
{
QMutexLocker locker(&m_mutex);
m_folders.clear();
}
QJsonObject fileObject = jsonDocument.object();
if (fileObject.value("version").toString() == FOLDER_CONFIG_VERSION) {
if (fileObject.contains("folders")) {
QJsonArray jsonArray = fileObject.value(QLatin1String("folders")).toArray();
for (const auto &value : jsonArray) {
QJsonObject object = value.toObject();
if (object.contains("name") && object.contains("id") && object.contains("apps")) {
FavoritesFolder folder;
folder.name = object.value(QLatin1String("name")).toString();
folder.id = object.value(QLatin1String("id")).toInt();
QJsonArray apps = object.value(QLatin1String("apps")).toArray();
for (const auto &app : apps) {
folder.apps.append(app.toString());
}
if (!folder.apps.isEmpty()) {
insertFolder(folder);
}
}
}
}
} else {
saveData();
return;
}
}
void FavoriteFolderHelper::saveData()
{
QFile file(s_folderConfigFile);
if (!file.open(QFile::WriteOnly)) {
return;
}
QJsonDocument jsonDocument;
QJsonObject fileObject;
QJsonArray folderArray;
{
QMutexLocker locker(&m_mutex);
for (const auto &folder : m_folders) {
QJsonObject object;
QJsonArray apps;
for (const auto &app : folder.apps) {
apps.append(app);
}
object.insert("name", folder.name);
object.insert("id", folder.id);
object.insert("apps", apps);
folderArray.append(object);
}
}
fileObject.insert("version", FOLDER_CONFIG_VERSION);
fileObject.insert("folders", folderArray);
jsonDocument.setObject(fileObject);
if (file.write(jsonDocument.toJson()) == -1) {
qWarning() << "Error saving configuration file.";
}
file.flush();
file.close();
}
QVariantList FavoriteFolderHelper::folderIcon(const FavoritesFolder &folder)
{
// TODO: 使用绘图API生成图片
QVariantList icons;
DataEntity app;
int count = qMin(folder.getDisplayApps().count(), FOLDER_MAX_ICON_NUM);
for (int i = 0; i < count; ++i) {
if (BasicAppModel::instance()->getAppById(folder.getDisplayApps().at(i), app)) {
QVariantMap icon;
icon["icon"] = app.icon();
icon["desktopName"] = app.desktopName();
icons.append(icon);
}
}
return icons;
}
QStringList FavoriteFolderHelper::appsInFolders()
{
QStringList apps;
for (const auto &folder : m_folders) {
apps.append(folder.apps);
}
return apps;
}
QStringList FavoritesFolder::getDisplayApps() const
{
QStringList list;
for (const QString &app : apps) {
if (SecurityFunctionControl::instance()->canAppDisplay(app)) {
list.append(app);
}
}
return list;
}
} // UkuiMenu
ukui-menu/src/extension/menu-extension-loader.h 0000664 0001750 0001750 00000003202 15160463353 020620 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_MENU_EXTENSION_LOADER_H
#define UKUI_MENU_MENU_EXTENSION_LOADER_H
#include
#include
#include
#include "widget-extension.h"
#include "context-menu-extension.h"
namespace UkuiMenu {
class MenuExtensionPlugin;
class MenuExtensionLoader
{
public:
static MenuExtensionLoader *instance();
QList widgets() const;
QList menus() const;
private:
MenuExtensionLoader();
void loadInternalExtension();
void loadExtensionFromDisk();
void loadExtensionFromDir(QDir dir);
void setBlackList(const QStringList &blackList);
void load();
void expand();
void registerExtension(MenuExtensionPlugin *plugin);
private:
QStringList m_blackList;
QList m_widgets;
QList m_menus;
static QHash plugins;
};
} // UkuiMenu
#endif //UKUI_MENU_MENU_EXTENSION_LOADER_H
ukui-menu/src/extension/widget-model.h 0000664 0001750 0001750 00000003255 15160463353 016767 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_WIDGET_MODEL_H
#define UKUI_MENU_WIDGET_MODEL_H
#include
#include
#include "widget-extension.h"
namespace UkuiMenu {
class WidgetModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(UkuiMenu::WidgetMetadata::Types types READ types WRITE setTypes)
Q_PROPERTY(UkuiMenu::WidgetMetadata::Flags flags READ flags WRITE setFlags)
public:
explicit WidgetModel(QObject *parent = nullptr);
Q_INVOKABLE void init();
Q_INVOKABLE void send(int index, const QVariantMap &data);
WidgetMetadata::Types types() const;
void setTypes(WidgetMetadata::Types types);
WidgetMetadata::Flags flags() const;
void setFlags(WidgetMetadata::Flags flags);
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
private:
WidgetMetadata::Types m_types = WidgetMetadata::Widget;
WidgetMetadata::Flags m_flags = WidgetMetadata::Normal;
};
}
#endif //UKUI_MENU_WIDGET_MODEL_H
ukui-menu/src/extension/extensions/ 0000775 0001750 0001750 00000000000 15160463353 016427 5 ustar feng feng ukui-menu/src/extension/extensions/favorite-extension.h 0000664 0001750 0001750 00000002620 15160463353 022431 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_FAVORITE_EXTENSION_H
#define UKUI_MENU_FAVORITE_EXTENSION_H
#include "../menu-extension-iface.h"
namespace UkuiMenu {
class FavoriteAppsModel;
class FavoriteExtension : public MenuExtensionIFace
{
Q_OBJECT
public:
explicit FavoriteExtension(QObject *parent = nullptr);
~FavoriteExtension();
void receive(QVariantMap data) override;
int index() override;
QString name() override;
QUrl url() override;
QVariantMap data() override;
private:
QVariantMap m_data;
FavoriteAppsModel *m_favoriteAppsModel = nullptr;
private:
void updateFavoriteData();
void openFavoriteApp(const QString &path);
};
} // UkuiMenu
#endif //UKUI_MENU_FAVORITE_EXTENSION_H
ukui-menu/src/extension/extensions/favorite-extension.cpp 0000664 0001750 0001750 00000015520 15160463353 022767 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "favorite-extension.h"
#include "app-data-manager.h"
#include "app-manager.h"
#include "commons.h"
#include "settings.h"
#include "event-track.h"
#include
#include
#include
#include
namespace UkuiMenu {
class FavoriteMenuProvider : public MenuProvider
{
public:
int index() override { return 512; }
bool isSupport(const RequestType &type) override;
QList generateActions(QObject *parent, const QVariant &data, const MenuInfo::Location &location, const QString &locationId) override;
};
class FavoriteAppsModel : public QAbstractListModel
{
Q_OBJECT
public:
enum RoleMessage
{
Id = Qt::UserRole,
Icon = Qt::UserRole + 1,
Name = Qt::UserRole + 2
};
explicit FavoriteAppsModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent) const override;
QHash roleNames() const override;
QVariant data(const QModelIndex &index, int role) const override;
void setFavoriteAppsData(QVector &apps);
Q_INVOKABLE void openMenu(const int &index);
public Q_SLOTS:
void exchangedAppsOrder(int startIndex, int endIndex);
void onStyleChanged(const GlobalSetting::Key &key);
private:
QVector m_favoriteAppsData;
UkuiSearch::ApplicationInfo *m_appInfoTable = nullptr;
};
FavoriteExtension::FavoriteExtension(QObject *parent) : MenuExtensionIFace(parent)
{
qRegisterMetaType("FavoriteAppsModel*");
MenuManager::instance()->registerMenuProvider(new FavoriteMenuProvider);
m_favoriteAppsModel = new FavoriteAppsModel(this);
m_data.insert("favoriteAppsModel", QVariant::fromValue(m_favoriteAppsModel));
updateFavoriteData();
connect(AppDataManager::instance(),&AppDataManager::favoriteAppChanged, this,&FavoriteExtension::updateFavoriteData);
connect(GlobalSetting::instance(), &GlobalSetting::styleChanged, m_favoriteAppsModel, &FavoriteAppsModel::onStyleChanged);
}
FavoriteExtension::~FavoriteExtension()
{
}
void FavoriteExtension::receive(QVariantMap data)
{
QString path = data.value("id").toString();
openFavoriteApp(path);
}
int FavoriteExtension::index()
{
return 0;
}
QString FavoriteExtension::name()
{
return tr("Favorite");
}
QUrl FavoriteExtension::url()
{
return {"qrc:///qml/extensions/FavoriteExtension.qml"};
}
QVariantMap FavoriteExtension::data()
{
return m_data;
}
void FavoriteExtension::openFavoriteApp(const QString &path)
{
AppManager::instance()->launchApp(path);
}
void FavoriteExtension::updateFavoriteData()
{
QVector favoriteApps = AppDataManager::instance()->favoriteApps();
m_favoriteAppsModel->setFavoriteAppsData(favoriteApps);
}
FavoriteAppsModel::FavoriteAppsModel(QObject *parent) : QAbstractListModel(parent)
{
m_appInfoTable = new UkuiSearch::ApplicationInfo(this);
}
int FavoriteAppsModel::rowCount(const QModelIndex &parent) const
{
return m_favoriteAppsData.count();
}
QHash FavoriteAppsModel::roleNames() const
{
QHash names;
names.insert(Id,"id");
names.insert(Icon,"icon");
names.insert(Name,"name");
return names;
}
QVariant FavoriteAppsModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
if (row < 0 || row > m_favoriteAppsData.count()) {
return {};
}
switch (role) {
case Id:
return m_favoriteAppsData.at(row).id();
case Icon:
return m_favoriteAppsData.at(row).icon();
case Name:
return m_favoriteAppsData.at(row).name();
default:
break;
}
return {};
}
void FavoriteAppsModel::setFavoriteAppsData(QVector &apps)
{
beginResetModel();
m_favoriteAppsData.swap(apps);
endResetModel();
}
void FavoriteAppsModel::openMenu(const int &index)
{
if (index < 0 || index >= m_favoriteAppsData.size()) {
return;
}
MenuManager::instance()->showMenu(m_favoriteAppsData.at(index), MenuInfo::Extension, "favorite");
}
void FavoriteAppsModel::exchangedAppsOrder(int startIndex, int endIndex)
{
int endNum = m_favoriteAppsData.at(endIndex).favorite();
QString startId = m_favoriteAppsData.at(startIndex).id();
AppDataManager::instance()->changedFavoriteOrderSignal(startId, endNum);
}
void FavoriteAppsModel::onStyleChanged(const GlobalSetting::Key &key)
{
if (key == GlobalSetting::IconThemeName) {
beginResetModel();
endResetModel();
}
}
bool FavoriteMenuProvider::isSupport(const MenuProvider::RequestType &type)
{
return type == DataType;
}
QList
FavoriteMenuProvider::generateActions(QObject *parent, const QVariant &data, const MenuInfo::Location &location,
const QString &locationId)
{
if (!parent) {
return {};
}
DataEntity app = data.value();
if (app.type() != DataType::Normal) {
return {};
}
QList list;
switch (location) {
case MenuInfo::AppList:
case MenuInfo::FolderPage:
case MenuInfo::Extension: {
if (app.favorite() == 0) {
list << new QAction(QObject::tr("Fix to favorite"), parent);
QObject::connect(list.last(), &QAction::triggered, parent, [app] {
Q_EMIT AppDataManager::instance()->fixToFavoriteSignal(app.id(), 1);
EventTrack::instance()->sendDefaultEvent("fix_to_favorite", "Right-click Menu");
});
} else if (locationId == "favorite") {
list << new QAction(QObject::tr("Remove from favorite"), parent);
QObject::connect(list.last(), &QAction::triggered, parent, [app] {
Q_EMIT AppDataManager::instance()->fixToFavoriteSignal(app.id(), 0);
EventTrack::instance()->sendDefaultEvent("remove_from_favorite", "Right-click Menu");
});
}
break;
}
case MenuInfo::FullScreen:
case MenuInfo::FullScreenFolder:
default:
break;
}
return list;
}
} // UkuiMenu
#include "favorite-extension.moc"
ukui-menu/src/extension/widget-extension-model.h 0000664 0001750 0001750 00000003125 15160463353 020775 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_WIDGET_EXTENSION_MODEL_H
#define UKUI_MENU_WIDGET_EXTENSION_MODEL_H
#include
namespace UkuiMenu {
class WidgetExtension;
class WidgetExtensionModel : public QAbstractListModel
{
Q_OBJECT
public:
static WidgetExtensionModel *instance();
explicit WidgetExtensionModel(QObject *parent = nullptr);
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash roleNames() const override;
Q_INVOKABLE UkuiMenu::WidgetExtension *widgetAt(int index) const;
Q_INVOKABLE void notify(int index, const QVariantMap &data) const;
private:
QList m_widgets;
};
} // UkuiMenu
#endif //UKUI_MENU_WIDGET_EXTENSION_MODEL_H
ukui-menu/src/extension/context-menu-manager.cpp 0000775 0001750 0001750 00000005434 15160463353 021003 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "context-menu-manager.h"
#include "menu-extension-loader.h"
#include "basic-app-filter-model.h"
#include
#include
#include
#include
using namespace UkuiMenu;
ContextMenuManager *ContextMenuManager::instance()
{
static ContextMenuManager manager;
return &manager;
}
class MenuManagerPrivate
{
public:
QPointer contextMenu;
QWindow *mainWindow {nullptr};
QList extensions;
};
ContextMenuManager::ContextMenuManager() : d(new MenuManagerPrivate)
{
d->extensions = MenuExtensionLoader::instance()->menus();
}
ContextMenuManager::~ContextMenuManager()
{
for (auto &provider : d->extensions) {
delete provider;
provider = nullptr;
}
}
void ContextMenuManager::showMenu(const QString &appid, const MenuInfo::Location location, const QString &lid, const QPoint &point)
{
DataEntity app;
if (BasicAppFilterModel::instance()->getAppById(appid, app)) {
showMenu(app, location, lid, point);
}
}
void ContextMenuManager::showMenu(const DataEntity &data, MenuInfo::Location location, const QString &lid, const QPoint &point)
{
if (closeMenu()) {
return;
}
auto menu = new QMenu;
QList actions;
for (const auto &extension : d->extensions) {
actions.append(extension->actions(data, menu, location, lid));
}
if (actions.isEmpty() && menu->isEmpty()) {
delete menu;
return;
}
d->contextMenu = menu;
menu->setAttribute(Qt::WA_DeleteOnClose);
if (menu->winId()) {
menu->windowHandle()->setTransientParent(d->mainWindow);
}
menu->addActions(actions);
menu->popup(checkPoint(point));
}
void ContextMenuManager::setMainWindow(QWindow *mainWindow)
{
d->mainWindow = mainWindow;
}
bool ContextMenuManager::closeMenu()
{
if (d->contextMenu) {
d->contextMenu.data()->close();
return true;
}
return false;
}
inline QPoint ContextMenuManager::checkPoint(const QPoint &rawPoint)
{
if (rawPoint.isNull()) {
return QCursor::pos();
}
return rawPoint;
}
ukui-menu/src/extension/menu/ 0000775 0001750 0001750 00000000000 15160463365 015177 5 ustar feng feng ukui-menu/src/extension/menu/app-menu-plugin.cpp 0000664 0001750 0001750 00000020056 15160463365 020724 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "app-menu-plugin.h"
#include "settings.h"
#include "app-manager.h"
#include "../context-menu-extension.h"
#include "basic-app-filter-model.h"
#include "user-config.h"
#include
#include
#include
#include
#include
#include
#include
namespace UkuiMenu {
class AppContentMenu : public ContextMenuExtension
{
public:
int index() const override;
QList actions(const DataEntity &data, QMenu *parent, const MenuInfo::Location &location,
const QString &locationId) override;
private:
static void addToTop(QObject *parent, const QString &appId, const int &appTop, QList &list);
static void addToPanelAction(QObject *parent, const QString &appId, QList &list);
static void addToDesktopAction(QObject *parent, const QString &appId, QList &list);
static void addUninstall(QObject *parent, const QString &appId, QList &list);
static void addRemoveFromList(QObject *parent, const QString &appId, const int &appLaunched, const QString &appInsertTime, QList &list);
};
int AppContentMenu::index() const
{
return ContextMenuExtension::index();
}
QList AppContentMenu::actions(const DataEntity &data, QMenu *parent, const MenuInfo::Location &location,
const QString &locationId)
{
if (!parent || (data.type() != DataType::Normal)) {
return {};
}
QList list;
QAction* actionSeparator = nullptr;
QString appId = data.id();
int appTop = data.top();
int appLaunched = data.launched();
QString appInsertTime = data.insertTime();
switch (location) {
case MenuInfo::AppList: {
//置顶
if (locationId == "all") {
addToTop(parent, appId, appTop, list);
}
}
case MenuInfo::Extension:
case MenuInfo::FolderPage:
case MenuInfo::FullScreen:
case MenuInfo::Folder:
// 添加到任务栏
addToPanelAction(parent, appId, list);
//添加到桌面快捷方式
addToDesktopAction(parent, appId, list);
//添加分割线
actionSeparator = new QAction;
actionSeparator->setSeparator(true);
list << actionSeparator;
//添加从当前列表移除
addRemoveFromList(parent, appId, appLaunched, appInsertTime, list);
// 卸载
if (data.removable()) {
addUninstall(parent, appId, list);
}
break;
default:
break;
}
if (!actionSeparator) {
actionSeparator->setVisible(list.last() != actionSeparator);
}
return list;
}
void AppContentMenu::addToTop(QObject *parent, const QString &appId, const int &appTop, QList &list)
{
QString actionName = (appTop == 0) ? QObject::tr("Fixed to all applications") : QObject::tr("Unfixed from all applications");
list << new QAction(actionName, parent);
QObject::connect(list.last(), &QAction::triggered, parent, [appId, appTop] {
BasicAppFilterModel::instance()->databaseInterface()->fixAppToTop(appId, appTop);
});
}
void AppContentMenu::addToPanelAction(QObject *parent, const QString &appId, QList &list)
{
QDBusInterface iface("org.ukui.taskManager", "/taskManager", "org.ukui.taskManager", QDBusConnection::sessionBus());
if (!iface.isValid()) {
qWarning() << "Ukui taskManager dbusinterface error";
return;
}
iface.setTimeout(1000);
QDBusReply isFixedOnTaskBar = iface.call("checkQuickLauncher", appId);
if (!isFixedOnTaskBar.isValid()) {
qWarning() << "Ukui taskManager dbusinterface call checkQuickLauncher timeout";
return;
}
QString actionName = isFixedOnTaskBar ? QObject::tr("Remove from taskbar") : QObject::tr("Add to taskbar");
QString functionName = isFixedOnTaskBar ? "removeQuickLauncher" : "addQuickLauncher";
QIcon icon = isFixedOnTaskBar ? QIcon::fromTheme("ukui-unfixed-symbolic") : QIcon::fromTheme("view-pin-symbolic");
list << new QAction(icon, actionName, parent);
QObject::connect(list.last(), &QAction::triggered, parent, [appId, functionName] {
QDBusInterface iface("org.ukui.taskManager", "/taskManager", "org.ukui.taskManager", QDBusConnection::sessionBus());
if (!iface.isValid()) {
qWarning() << "Ukui taskManager dbusinterface error";
return;
}
iface.setTimeout(1);
QDBusReply ret = iface.call(functionName, appId);
if (!ret.isValid() || !ret) {
qWarning() << "Add/Remove from taskbar error";
}
});
}
void AppContentMenu::addToDesktopAction(QObject *parent, const QString &appId, QList &list)
{
list << new QAction(QIcon::fromTheme("emblem-link2-symbolic"), QObject::tr("Send to desktop shortcuts"), parent);
QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
QString path = QString(desktopPath + "/" + QFileInfo(appId).fileName());
if (QFile::exists(path)) {
list.last()->setEnabled(false);
return;
}
QObject::connect(list.last(), &QAction::triggered, parent, [appId, path] {
if (QFile::copy(appId, path)) {
// 设置权限755
// QFile::Permissions permissions(0x0755); // 这也是可以的
QFile::Permissions permissions = {
QFile::ReadUser | QFile::WriteUser | QFile::ExeUser |
QFile::ReadGroup | QFile::ExeGroup |
QFile::ReadOther | QFile::ExeOther
};
if (!QFile::setPermissions(path, permissions)) {
qWarning() << "set file permissions failed, file:" << path;
}
}
});
}
void AppContentMenu::addUninstall(QObject *parent, const QString &appId, QList &list)
{
list << new QAction(QIcon::fromTheme("user-trash-symbolic"), QObject::tr("Uninstall"), parent);
QObject::connect(list.last(), &QAction::triggered, parent, [appId] {
AppManager::instance()->launchBinaryApp("kylin-uninstaller", appId);
});
}
void AppContentMenu::addRemoveFromList(QObject *parent, const QString &appId, const int &appLaunched, const QString &appInsertTime, QList &list)
{
if (appLaunched == 1) return;
if (UserConfig::instance()->isPreInstalledApps(appId)) return;
QDateTime installDate = QDateTime::fromString(appInsertTime, "yyyy-MM-dd hh:mm:ss");
if (!installDate.isValid()) return;
QDateTime currentDateTime = QDateTime::currentDateTime();
qint64 xt = currentDateTime.toSecsSinceEpoch() - installDate.toSecsSinceEpoch();
if ((xt >= 0) && (xt <= 30 * 24 * 3600)) {
list << new QAction(QIcon::fromTheme("edit-delete-symbolic"), QObject::tr("Remove from List"), parent);
QObject::connect(list.last(), &QAction::triggered, parent, [appId] {
BasicAppFilterModel::instance()->databaseInterface()->updateApLaunchedState(appId, true);
});
}
}
// ====== AppMenuPlugin ====== //
QString AppMenuPlugin::id()
{
return QStringLiteral("app-menu");
}
WidgetExtension *AppMenuPlugin::createWidgetExtension()
{
return nullptr;
}
ContextMenuExtension *AppMenuPlugin::createContextMenuExtension()
{
return new AppContentMenu;
}
} // UkuiMenu
ukui-menu/src/extension/menu/app-menu-plugin.h 0000664 0001750 0001750 00000002131 15160463353 020360 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_APP_MENU_PLUGIN_H
#define UKUI_MENU_APP_MENU_PLUGIN_H
#include "../menu-extension-plugin.h"
namespace UkuiMenu {
class AppMenuPlugin : public MenuExtensionPlugin
{
Q_OBJECT
public:
QString id() override;
WidgetExtension *createWidgetExtension() override;
ContextMenuExtension *createContextMenuExtension() override;
};
} // UkuiMenu
#endif //UKUI_MENU_APP_MENU_PLUGIN_H
ukui-menu/src/extension/widget-extension.cpp 0000664 0001750 0001750 00000002073 15160463353 020233 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "widget-extension.h"
namespace UkuiMenu {
WidgetExtension::WidgetExtension(QObject *parent) : QObject(parent)
{
qRegisterMetaType();
}
int WidgetExtension::index() const
{
return -1;
}
QVariantMap WidgetExtension::data()
{
return {};
}
void WidgetExtension::receive(const QVariantMap &data)
{
Q_UNUSED(data)
}
} // UkuiMenu
ukui-menu/src/extension/menu-extension-loader.cpp 0000664 0001750 0001750 00000010506 15160463353 021160 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "menu-extension-loader.h"
#include "menu-extension-plugin.h"
#include "menu/app-menu-plugin.h"
#include "favorite/favorite-extension-plugin.h"
#include
namespace UkuiMenu {
QHash MenuExtensionLoader::plugins = QHash();
MenuExtensionLoader *MenuExtensionLoader::instance()
{
static MenuExtensionLoader loader;
return &loader;
}
MenuExtensionLoader::MenuExtensionLoader()
{
// setBlackList({});
load();
}
void MenuExtensionLoader::load()
{
loadInternalExtension();
loadExtensionFromDisk();
expand();
}
void MenuExtensionLoader::loadInternalExtension()
{
registerExtension(new FavoriteExtensionPlugin);
registerExtension(new AppMenuPlugin);
}
void MenuExtensionLoader::loadExtensionFromDisk()
{
QDir usrDir(UKUI_MENU_EXTENSION_DIR);
loadExtensionFromDir(usrDir);
QDir optDir("/opt/system/lib/ukui-menu/extensions");
loadExtensionFromDir(optDir);
}
void MenuExtensionLoader::loadExtensionFromDir(QDir dir)
{
for(const QString& fileName : dir.entryList({"*.so"},QDir::Files)) {
QPluginLoader pluginLoader(dir.absoluteFilePath(fileName));
QJsonObject metaData = pluginLoader.metaData().value("MetaData").toObject();
QString type = metaData.value("Type").toString();
QString version = metaData.value("Version").toString();
if(type != UKUI_MENU_EXTENSION_I_FACE_TYPE) {
continue;
}
if(version != UKUI_MENU_EXTENSION_I_FACE_VERSION) {
qWarning() << "UKUI_MENU_EXTENSION version check failed:" << fileName << "version:" << version << "iface version : " << UKUI_MENU_EXTENSION_I_FACE_VERSION;
continue;
}
QObject *obj = pluginLoader.instance();
if (!obj) {
continue;
}
MenuExtensionPlugin *plugin = qobject_cast(obj);
if (!plugin) {
continue;
}
registerExtension(plugin);
}
}
void MenuExtensionLoader::expand()
{
for (const auto &plugin : MenuExtensionLoader::plugins) {
// qDebug() << "Expand Extension:" << plugin->id();
WidgetExtension *widget = plugin->createWidgetExtension();
if (widget) {
// register widget.
m_widgets.append(widget);
}
ContextMenuExtension *contextMenu = plugin->createContextMenuExtension();
if (contextMenu) {
// 注册菜单
m_menus.append(contextMenu);
}
}
std::sort(m_widgets.begin(), m_widgets.end(), [] (const WidgetExtension *a, const WidgetExtension *b) {
if (a->index() < 0) {
return false;
} else if (b->index() < 0) {
return true;
}
return a->index() <= b->index();
});
std::sort(m_menus.begin(), m_menus.end(), [] (const ContextMenuExtension *a, const ContextMenuExtension *b) {
if (a->index() < 0) {
return false;
} else if (b->index() < 0) {
return true;
}
return a->index() <= b->index();
});
}
void MenuExtensionLoader::setBlackList(const QStringList &blackList)
{
m_blackList = blackList;
}
QList MenuExtensionLoader::widgets() const
{
return m_widgets;
}
QList MenuExtensionLoader::menus() const
{
return m_menus;
}
void MenuExtensionLoader::registerExtension(MenuExtensionPlugin *plugin)
{
QString id = plugin->id();
if (m_blackList.contains(id) || MenuExtensionLoader::plugins.contains(id)) {
delete plugin;
return;
}
MenuExtensionLoader::plugins.insert(id, plugin);
}
} // UkuiMenu
ukui-menu/src/ukui-menu-application.cpp 0000664 0001750 0001750 00000021005 15160463365 017141 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "ukui-menu-application.h"
#include "menu-dbus-service.h"
#include "settings.h"
#include "commons.h"
#include "menu-main-window.h"
#include "power-button.h"
#include "app-manager.h"
#include "context-menu-manager.h"
#include "event-track.h"
#include "sidebar-button-utils.h"
#include "widget-model.h"
#include "app-page-backend.h"
#include "app-group-model.h"
#include "favorite/folder-model.h"
#include "favorite/favorite-filter-model.h"
#include "security-function-control.h"
#include
#include
#include
#include
#include
using namespace UkuiMenu;
UkuiMenuApplication::UkuiMenuApplication(MenuMessageProcessor *processor) : QObject(nullptr)
{
registerQmlTypes();
startUkuiMenu();
initDbusService();
connect(processor, &MenuMessageProcessor::request, this, &UkuiMenuApplication::execCommand);
}
void UkuiMenuApplication::startUkuiMenu()
{
initQmlEngine();
loadMenuUI();
}
void UkuiMenuApplication::registerQmlTypes()
{
const char *uri = "org.ukui.menu.core";
int versionMajor = 1, versionMinor = 0;
SettingModule::defineModule(uri, versionMajor, versionMinor);
WindowModule::defineModule(uri, versionMajor, versionMinor);
PowerButton::defineModule(uri, versionMajor, versionMinor);
SidebarButtonUtils::defineModule(uri, versionMajor, versionMinor);
qmlRegisterType(uri, versionMajor, versionMinor, "WidgetModel");
qmlRegisterType(uri, versionMajor, versionMinor, "AppGroupModel");
//qmlRegisterType(uri, versionMajor, versionMinor, "AppPageBackend");
qmlRegisterSingletonInstance(uri, versionMajor, versionMinor, "AppPageBackend", AppPageBackend::instance());
qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "PluginGroup", "Use enums only.");
// commons
qRegisterMetaType("DataType::Type");
qRegisterMetaType("DataEntity");
qRegisterMetaType("MenuInfo::Location");
qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "Display", "Use enums only.");
qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "DataType", "Use enums only");
qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "MenuInfo", "Use enums only.");
qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "LabelItem", "Use enums only.");
qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "WidgetMetadata", "Use enums only.");
// qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "DataEntity", "unknown");
qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "EventTrack", "Attached only.");
}
void UkuiMenuApplication::initQmlEngine()
{
m_engine = new QQmlEngine(this);
m_engine->addImportPath("qrc:/qml");
QQmlContext *context = m_engine->rootContext();
context->setContextProperty("menuSetting", MenuSetting::instance());
context->setContextProperty("menuManager", ContextMenuManager::instance());
context->setContextProperty("appManager", AppManager::instance());
context->setContextProperty("favoriteModel", FavoriteFilterModel::instance());
context->setContextProperty("FolderModel", &FolderModel::instance());
context->setContextProperty("functionControl", SecurityFunctionControl::instance());
// MenuMainWindow
// const QUrl url(QStringLiteral("qrc:/qml/MenuMainWindow.qml"));
// QQmlApplicationEngine *m_applicationEngine{nullptr};
// m_applicationEngine = new QQmlApplicationEngine(this);
// QObject::connect(m_applicationEngine, &QQmlApplicationEngine::objectCreated,
// this, [url](QObject *obj, const QUrl &objUrl) {
// if (!obj && url == objUrl)
// QCoreApplication::exit(-1);
// }, Qt::QueuedConnection);
//
// m_applicationEngine->load(url);
connect(AppManager::instance(), &AppManager::request, this, &UkuiMenuApplication::execCommand);
}
void UkuiMenuApplication::loadMenuUI()
{
const QUrl url(QStringLiteral("qrc:/qml/main.qml"));
m_mainWindow = new MenuWindow(m_engine, nullptr);
m_mainWindow->setSource(url);
connect(m_mainWindow, &QQuickView::activeFocusItemChanged, m_mainWindow, [this] {
if (m_mainWindow->activeFocusItem()) {
return;
}
execCommand(Hide);
});
}
void UkuiMenuApplication::initDbusService()
{
m_menuDbusService = new MenuDbusService(QGuiApplication::instance()->property("display").toString(), this);
if (m_menuDbusService) {
connect(m_menuDbusService, &MenuDbusService::menuActive, this, [this] {
execCommand(Active);
});
// connect(m_menuDbusService, &MenuDbusService::reloadConfigSignal, this, [this] {
//// reload ...
// });
}
}
void UkuiMenuApplication::execCommand(Command command)
{
switch (command) {
case Active: {
if (m_mainWindow) {
m_mainWindow->activeMenuWindow(!m_mainWindow->isVisible());
}
break;
}
case Show: {
if (m_mainWindow) {
m_mainWindow->activeMenuWindow(true);
}
break;
}
case Quit: {
if (m_mainWindow) {
m_mainWindow->activeMenuWindow(false);
m_engine->quit();
}
QCoreApplication::quit();
break;
}
case Hide: {
if (m_mainWindow) {
m_mainWindow->activeMenuWindow(false);
}
break;
}
default:
break;
}
// TODO: 发送窗口显示隐藏信号到插件
}
UkuiMenuApplication::~UkuiMenuApplication()
{
if (m_mainWindow) {
m_mainWindow->deleteLater();
}
}
// == MenuMessageProcessor == //
QCommandLineOption MenuMessageProcessor::showUkuiMenu({"s", "show"}, QObject::tr("Show ukui-menu."));
QCommandLineOption MenuMessageProcessor::quitUkuiMenu({"q", "quit"}, QObject::tr("Quit ukui-menu."));
MenuMessageProcessor::MenuMessageProcessor() : QObject(nullptr) {}
void MenuMessageProcessor::processMessage(const QString &message)
{
QStringList options = QString(message).split(' ');
QCommandLineParser parser;
parser.addOption(MenuMessageProcessor::showUkuiMenu);
parser.addOption(MenuMessageProcessor::quitUkuiMenu);
parser.parse(options);
if (parser.isSet(MenuMessageProcessor::showUkuiMenu)) {
Q_EMIT request(UkuiMenuApplication::Show);
return;
}
if (parser.isSet(MenuMessageProcessor::quitUkuiMenu)) {
Q_EMIT request(UkuiMenuApplication::Quit);
return;
}
}
/**
* 已知问题,使用命令quit时,会出现 QFileSystemWatcher::removePaths: list is empty
* 可见该bug: https://bugreports.qt.io/browse/QTBUG-68607
* @param message
* @return
*/
bool MenuMessageProcessor::preprocessMessage(const QStringList& message)
{
qDebug() << "Hey, there.";
QCommandLineParser parser;
QCommandLineOption helpOption = parser.addHelpOption();
QCommandLineOption versionOption = parser.addVersionOption();
parser.addOption(MenuMessageProcessor::showUkuiMenu);
parser.addOption(MenuMessageProcessor::quitUkuiMenu);
parser.parse(message);
if (message.size() <= 1 || parser.isSet(helpOption) || !parser.unknownOptionNames().isEmpty()) {
if (!parser.unknownOptionNames().isEmpty()) {
qDebug() << "Unknown options:" << parser.unknownOptionNames();
}
parser.showHelp();
return false;
}
if (parser.isSet(versionOption)) {
parser.showVersion();
return false;
}
return parser.isSet(MenuMessageProcessor::showUkuiMenu) || parser.isSet(MenuMessageProcessor::quitUkuiMenu);
}
ukui-menu/src/data-entity.cpp 0000664 0001750 0001750 00000021624 15160463353 015150 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "data-entity.h"
using namespace UkuiMenu;
class DataEntityPrivate
{
public:
DataEntityPrivate() = default;
DataEntityPrivate(DataType::Type type, QString name, QString icon, QString comment, QString extraData)
: type(type), name(std::move(name)), icon(std::move(icon)), comment(std::move(comment)), extraData(std::move(extraData)) {}
bool lock{false}; // 应用锁定
bool recentInstall{false};
int launched{0}; // 是否启动过
int top{0}; // 置顶状态及序号
int favorite{0}; // 收藏状态及序号
int launchTimes{0}; // 启动次数
double priority{0};
DataType::Type type {DataType::Normal};
QString id; // 应用可执行文件路径
QString icon;
QString name;
QString category;
QString firstLetter;
QString comment; // 应用描述
QString extraData; // 额外的数据
QString insertTime; //安装的时间
QString group; // 分类
bool removable; // 可否卸载
QString desktopName; // 应用desktop文件名称
};
DataEntity::DataEntity() : d(new DataEntityPrivate) {}
DataEntity::DataEntity(DataType::Type type, const QString& name, const QString& icon, const QString& comment, const QString& extraData)
: d(new DataEntityPrivate(type, name, icon, comment, extraData))
{
}
int DataEntity::top() const
{
return d->top;
}
void DataEntity::setTop(int top)
{
d->top = top;
}
bool DataEntity::isLock() const
{
return d->lock;
}
void DataEntity::setLock(bool lock)
{
d->lock = lock;
}
bool DataEntity::isRecentInstall() const
{
return d->recentInstall;
}
void DataEntity::setRecentInstall(bool recentInsatll)
{
d->recentInstall = recentInsatll;
}
int DataEntity::launched() const
{
return d->launched;
}
void DataEntity::setLaunched(int launched)
{
d->launched = launched;
}
int DataEntity::favorite() const
{
return d->favorite;
}
void DataEntity::setFavorite(int favorite)
{
d->favorite = favorite;
}
int DataEntity::launchTimes() const
{
return d->launchTimes;
}
void DataEntity::setLaunchTimes(int launchTimes)
{
d->launchTimes = launchTimes;
}
double DataEntity::priority() const
{
return d->priority;
}
void DataEntity::setPriority(double priority)
{
d->priority = priority;
}
QString DataEntity::insertTime() const
{
return d->insertTime;
}
void DataEntity::setInsertTime(const QString &insertTime)
{
d->insertTime = insertTime;
}
QString DataEntity::id() const
{
return d->id;
}
void DataEntity::setId(const QString &id)
{
d->id = id;
setDesktopName(QFileInfo(id).completeBaseName());
}
void DataEntity::setCategory(const QString &category)
{
d->category = category;
}
QString DataEntity::category() const
{
return d->category;
}
void DataEntity::setFirstLetter(const QString &firstLetter)
{
d->firstLetter = firstLetter;
}
QString DataEntity::firstLetter() const
{
return d->firstLetter;
}
void DataEntity::setType(DataType::Type type)
{
d->type = type;
}
DataType::Type DataEntity::type() const
{
return d->type;
}
void DataEntity::setIcon(const QString &icon)
{
d->icon = icon;
}
QString DataEntity::icon() const
{
return d->icon;
}
void DataEntity::setName(const QString &name)
{
d->name = name;
}
QString DataEntity::name() const
{
return d->name;
}
void DataEntity::setComment(const QString &comment)
{
d->comment = comment;
}
QString DataEntity::comment() const
{
return d->comment;
}
void DataEntity::setExtraData(const QString &extraData)
{
d->extraData = extraData;
}
QString DataEntity::extraData() const
{
return d->extraData;
}
QHash DataEntity::AppRoleNames()
{
QHash names;
names.insert(DataEntity::Id, "id");
names.insert(DataEntity::Type, "type");
names.insert(DataEntity::Icon, "icon");
names.insert(DataEntity::Name, "name");
names.insert(DataEntity::Comment, "comment");
names.insert(DataEntity::ExtraData, "extraData");
names.insert(DataEntity::Category, "category");
names.insert(DataEntity::Group, "group");
names.insert(DataEntity::FirstLetter, "firstLetter");
names.insert(DataEntity::InstallationTime, "installationTime");
names.insert(DataEntity::IsLaunched, "isLaunched");
names.insert(DataEntity::LaunchTimes, "launchTimes");
names.insert(DataEntity::IsLocked, "isLocked");
names.insert(DataEntity::Favorite, "favorite");
names.insert(DataEntity::Top, "top");
names.insert(DataEntity::RecentInstall, "recentInstall");
names.insert(DataEntity::Entity, "entity");
names.insert(DataEntity::DesktopName, "desktopName");
return names;
}
DataEntity::DataEntity(const DataEntity &other) : d(new DataEntityPrivate)
{
*d = *(other.d);
}
DataEntity& DataEntity::operator=(const DataEntity &other)
{
if (this != &other) {
*d = *(other.d);
}
return *this;
}
DataEntity::DataEntity(DataEntity &&other) noexcept : d(new DataEntityPrivate)
{
*d = *(other.d);
}
DataEntity &DataEntity::operator=(DataEntity &&other) noexcept
{
*d = *(other.d);
return *this;
}
DataEntity::~DataEntity()
{
if (d) {
delete d;
d = nullptr;
}
}
QVariant DataEntity::getValue(DataEntity::PropertyName property) const
{
switch (property) {
case Id:
return d->id;
case Type:
return d->type;
case Icon:
return d->icon;
case Name:
return d->name;
case Comment:
return d->comment;
case ExtraData:
return d->extraData;
case Category:
return d->category;
case Group:
return d->group;
case FirstLetter:
return d->firstLetter;
case InstallationTime:
return d->insertTime;
case IsLaunched:
return d->launched;
case LaunchTimes:
return d->launchTimes;
case IsLocked:
return d->lock;
case Favorite:
return d->favorite;
case Top:
return d->top;
case RecentInstall:
return d->recentInstall;
case Entity:
return QVariant::fromValue(*this);
case DesktopName:
return d->desktopName;
default:
break;
}
return {};
}
void DataEntity::setValue(DataEntity::PropertyName property, const QVariant &value)
{
switch (property) {
case Id:
d->id = value.toString();
break;
case Type:
d->type = value.value();
break;
case Icon:
d->icon = value.toString();
break;
case Name:
d->name = value.toString();
break;
case Comment:
d->comment = value.toString();
break;
case ExtraData:
d->extraData = value.toString();
break;
case Category:
d->category = value.toString();
break;
case Group:
d->group = value.toString();
break;
case FirstLetter:
d->firstLetter = value.toString();
break;
case InstallationTime:
d->insertTime = value.toString();
break;
case IsLaunched:
d->launched = value.toBool();
break;
case LaunchTimes:
d->launchTimes = value.toInt();
break;
case IsLocked:
d->lock = value.toBool();
break;
case Favorite:
d->favorite = value.toInt();
break;
case Top:
d->top = value.toInt();
break;
case RecentInstall:
d->recentInstall = value.toBool();
break;
default:
break;
}
}
void DataEntity::setGroup(const QString &group)
{
d->group = group;
}
QString DataEntity::group() const
{
return d->group;
}
void DataEntity::setRemovable(bool removable)
{
d->removable = removable;
}
bool DataEntity::removable() const
{
return d->removable;
}
void DataEntity::setDesktopName(const QString &desktopName)
{
d->desktopName = desktopName;
}
QString DataEntity::desktopName() const
{
return d->desktopName;
}
ukui-menu/src/menu-dbus-service.h 0000664 0001750 0001750 00000003341 15160463365 015726 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef MENU_DBUS_SERVICE_H
#define MENU_DBUS_SERVICE_H
#include
#include
class MenuAdaptor;
class QDBusServiceWatcher;
namespace UkuiMenu {
class MenuDbusService : public QObject, public QDBusContext
{
Q_OBJECT
public:
explicit MenuDbusService(const QString& display, QObject *parent = nullptr);
public Q_SLOTS:
void WinKeyResponse();
QString GetSecurityConfigPath();
void ReloadSecurityConfig();
void active(const QString &display);
Q_SIGNALS:
void menuActive();
void reloadConfigSignal();
private Q_SLOTS:
void activeMenu(QString display);
void onServiceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner);
private:
static QString displayFromPid(uint pid);
bool registerService();
void initWatcher();
void connectToActiveRequest();
void disConnectActiveRequest();
private:
QString m_display {};
MenuAdaptor *m_menuAdaptor {nullptr};
QDBusServiceWatcher *m_watcher {nullptr};
};
}
#endif // MENU_DBUS_SERVICE_H
ukui-menu/src/main.cpp 0000664 0001750 0001750 00000015364 15160463365 013660 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: hxf
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "qtsingleapplication.h"
#include "ukui-menu-application.h"
#define LOG_FILE_COUNT 2
#define MAX_LOG_FILE_SIZE 4194304
#define MAX_LOG_CHECK_INTERVAL 43200000
static int logFileId = -1;
static QString logFile = "ukui-menu.log";
static QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.log/ukui-menu/";
static QString logFileName = logFilePath + "ukui-menu-%1.log";
static quint64 startupTime;
bool checkFileSize(const QString &fileName) {
return QFile(fileName).size() < MAX_LOG_FILE_SIZE;
}
void clearFile(const QString &fileName) {
QFile file(fileName);
file.open(QIODevice::WriteOnly);
file.write("");
file.flush();
file.close();
}
void initLogFile() {
QDir dir;
if (!dir.exists(logFilePath)) {
if (!dir.mkpath(logFilePath)) {
qWarning() << "Unable to create" << logFilePath;
return;
}
}
for (int i = 0; i < LOG_FILE_COUNT; ++i) {
logFile = logFileName.arg(i);
if (QFile::exists(logFile)) {
if (checkFileSize(logFile)) {
logFileId = i;
break;
}
} else {
QFile file(logFile);
file.open(QIODevice::WriteOnly);
file.close();
}
}
if (logFileId < 0) {
logFileId = 0;
logFile = logFileName.arg(logFileId);
clearFile(logFile);
}
qInfo() << "init log file:" << logFile;
}
void checkLogFile() {
quint64 logTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
quint64 spacing = std::max(logTime, startupTime) - std::min(logTime, startupTime);
if (spacing <= MAX_LOG_CHECK_INTERVAL || checkFileSize(logFile)) {
return;
}
logFileId = ((logFileId + 1) % LOG_FILE_COUNT);
logFile = logFileName.arg(logFileId);
if (!checkFileSize(logFile)) {
clearFile(logFile);
}
}
void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
checkLogFile();
QByteArray localMsg = msg.toLocal8Bit();
QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit();
const char *file = context.file ? context.file : "";
const char *function = context.function ? context.function : "";
FILE *log_file = fopen(logFile.toLocal8Bit().constData(), "a+");
switch (type) {
case QtDebugMsg:
if (!log_file) {
break;
}
fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtInfoMsg:
fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtWarningMsg:
fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtCriticalMsg:
fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtFatalMsg:
fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
}
if (log_file) {
fclose(log_file);
}
}
int main(int argc, char *argv[])
{
startupTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
#ifndef UKUI_MENU_LOG_FILE_DISABLE
initLogFile();
qInstallMessageHandler(messageOutput);
#endif
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#else
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
QCoreApplication::setApplicationName("ukui-menu");
QCoreApplication::setOrganizationName("ukui");
QCoreApplication::setOrganizationDomain("ukui.org");
QCoreApplication::setApplicationVersion("0.0.1-alpha");
QString display;
if (UkuiQuick::WindowProxy::isWayland()) {
display = QLatin1String(getenv("WAYLAND_DISPLAY"));
} else {
display = QLatin1String(getenv("DISPLAY"));
}
QString appid = QString("ukui-menu-%1").arg(display);
qDebug() << "ukui-menu launch with:" << display << "appid:" << appid;
QtSingleApplication app(appid, argc, argv);
QGuiApplication::instance()->setProperty("display", display);
QTranslator translator;
QString translationFile{(QString(UKUI_MENU_TRANSLATION_DIR) + "/ukui-menu_" + QLocale::system().name() + ".qm")};
// translation files
if (QFile::exists(translationFile) && translator.load(translationFile)) {
QCoreApplication::installTranslator(&translator);
} else {
qWarning() << "Unable to load translation file:" << translationFile;
}
UkuiMenu::MenuMessageProcessor messageProcessor;
if (app.isRunning()) {
if (UkuiMenu::MenuMessageProcessor::preprocessMessage(QtSingleApplication::arguments())) {
app.sendMessage(QtSingleApplication::arguments().join(" ").toUtf8());
}
return 0;
}
UkuiMenu::UkuiMenuApplication menuApplication(&messageProcessor);
messageProcessor.processMessage(QtSingleApplication::arguments().join(" ").toUtf8());
QObject::connect(&app, &QtSingleApplication::messageReceived,
&messageProcessor, &UkuiMenu::MenuMessageProcessor::processMessage);
qInfo() << "ukui-menu startup time:" << (QDateTime::currentDateTime().toMSecsSinceEpoch() - startupTime)
<< ",date:" << QDateTime::currentDateTime().toString();
return QtSingleApplication::exec();
}
ukui-menu/src/utils/ 0000775 0001750 0001750 00000000000 15160463365 013357 5 ustar feng feng ukui-menu/src/utils/user-info-item.cpp 0000664 0001750 0001750 00000007725 15160463353 016736 0 ustar feng feng #include "user-info-item.h"
#include
#include
#include
#include
#define KYLIN_ACCOUNT_INFORMATION_NAME "org.freedesktop.Accounts"
#define KYLIN_ACCOUNT_INFORMATION_PATH "/org/freedesktop/Accounts"
#define KYLIN_ACCOUNT_INFORMATION_INTERFACE "org.freedesktop.Accounts"
#define DEFAULT_USER_ICON_FILE ":/res/icon/default-community-image.png"
using namespace UkuiMenu;
UkuiMenu::UserInfoItem::UserInfoItem(QString objectPath, QObject *parent) : QObject(parent)
{
m_objPath = objectPath;
initUserInfo();
createCircularIcon();
QDBusConnection::systemBus().connect(KYLIN_ACCOUNT_INFORMATION_NAME, objectPath,
"org.freedesktop.DBus.Properties", "PropertiesChanged",
this, SLOT(userInfoUpdateSlot(QString, QMap, QStringList)));
}
void UserInfoItem::initUserInfo()
{
m_isCurrentUser = false;
m_isLogged = false;
m_autoLogin = false;
QDBusInterface userInterface(KYLIN_ACCOUNT_INFORMATION_NAME,
m_objPath,
"org.freedesktop.DBus.Properties",
QDBusConnection::systemBus());
QDBusReply > reply = userInterface.call("GetAll", "org.freedesktop.Accounts.User");
if (reply.isValid()) {
QMap propertyMap;
propertyMap = reply.value();
m_userName = propertyMap.find("UserName").value().toString();
m_realName = propertyMap.find("RealName").value().toString();
m_accountType = propertyMap.find("AccountType").value().toInt();
m_iconFile = propertyMap.find("IconFile").value().toString();
m_passwdType = propertyMap.find("PasswordMode").value().toInt();
m_uid = propertyMap.find("Uid").value().toInt();
m_autoLogin = propertyMap.find("AutomaticLogin").value().toBool();
if (m_userName == QString(qgetenv("USER"))) {
m_isCurrentUser = true;
m_isLogged = true;
}
} else {
qWarning() << "UserInfoItem::initUserInfo: 'org.freedesktop.Accounts.User' dbus reply is invalid";
}
}
void UserInfoItem::createCircularIcon()
{
QPixmap sourcePixmap(m_iconFile);
if (sourcePixmap.isNull()) {
qWarning() << "UserInfoItem::createCircularIcon: Can't load icon file: " << m_iconFile;
return;
}
int diameter = std::min(sourcePixmap.height(), sourcePixmap.width());
QPixmap circularPixmap(diameter, diameter);
circularPixmap.fill(Qt::transparent);
QPainter painter(&circularPixmap);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
QPainterPath path;
path.addEllipse(0, 0, diameter, diameter);
painter.setClipPath(path);
QRect targetRect, sourceRect;
targetRect = QRect(0, 0, diameter, diameter);
if (sourcePixmap.width() > sourcePixmap.height()) {
sourceRect = QRect((sourcePixmap.width() - diameter) / 2, 0, diameter, diameter);
} else {
sourceRect = QRect(0, (sourcePixmap.height() - diameter) / 2, diameter, diameter);
}
painter.drawPixmap(targetRect, sourcePixmap, sourceRect);
m_circularIcon = QIcon(circularPixmap);
}
void UserInfoItem::userInfoUpdateSlot(const QString &property, const QMap &propertyMap, const QStringList &propertyList)
{
Q_UNUSED(property)
Q_UNUSED(propertyList)
QStringList keys = propertyMap.keys();
if (keys.contains("IconFile")) {
m_iconFile = propertyMap.value("IconFile").toString();
createCircularIcon();
}
if (keys.contains("UserName")) {
m_userName = propertyMap.value("UserName").toString();
}
if (keys.contains("RealName")) {
m_realName = propertyMap.value("RealName").toString();
}
if (keys.contains("AccountType")) {
m_accountType = propertyMap.value("AccountType").toInt();
}
Q_EMIT userInfoChanged();
}
ukui-menu/src/utils/app-manager.cpp 0000664 0001750 0001750 00000011450 15160463353 016251 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "app-manager.h"
#include "basic-app-filter-model.h"
#include
#include
#include
#include
#include
#include
#define KYLIN_APP_MANAGER_NAME "com.kylin.ProcessManager"
#define KYLIN_APP_MANAGER_PATH "/com/kylin/ProcessManager/AppLauncher"
#define KYLIN_APP_MANAGER_INTERFACE "com.kylin.ProcessManager.AppLauncher"
namespace UkuiMenu {
AppManager *AppManager::instance()
{
static AppManager instance(nullptr);
return &instance;
}
AppManager::AppManager(QObject *parent) : QObject(parent)
{
}
void AppManager::launchApp(const QString &appid)
{
if (appid.isEmpty()) {
return;
}
Q_EMIT request(UkuiMenuApplication::Hide);
QDBusMessage message = QDBusMessage::createMethodCall(KYLIN_APP_MANAGER_NAME, KYLIN_APP_MANAGER_PATH, KYLIN_APP_MANAGER_INTERFACE, "LaunchApp");
message << appid;
auto watcher = new QDBusPendingCallWatcher(QDBusPendingCall(QDBusConnection::sessionBus().asyncCall(message)), this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [appid] (QDBusPendingCallWatcher *self) {
if (self->isError()) {
QStringList list = parseDesktopFile(appid);
if (!list.isEmpty()) {
QString cmd = list.takeFirst();
QProcess::startDetached(cmd, list);
qDebug() << "launch with QProcess:" << cmd << list;
}
}
self->deleteLater();
});
BasicAppFilterModel::instance()->databaseInterface()->updateApLaunchedState(appid, true);
}
void AppManager::launchBinaryApp(const QString &app, const QString &args)
{
if (app.isEmpty()) {
return;
}
QDBusMessage message = QDBusMessage::createMethodCall(KYLIN_APP_MANAGER_NAME, KYLIN_APP_MANAGER_PATH, KYLIN_APP_MANAGER_INTERFACE, "LaunchApp");
message << app << args;
auto watcher = new QDBusPendingCallWatcher(QDBusPendingCall(QDBusConnection::sessionBus().asyncCall(message)), this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [app, args] (QDBusPendingCallWatcher *self) {
if (self->isError()) {
QProcess::startDetached(app, {args}, "");
}
self->deleteLater();
});
}
void AppManager::launchAppWithArguments(const QString &appid, const QStringList &args, const QString &applicationName)
{
if (appid.isEmpty()) {
return;
}
Q_EMIT request(UkuiMenuApplication::Hide);
QDBusMessage message = QDBusMessage::createMethodCall(KYLIN_APP_MANAGER_NAME,
KYLIN_APP_MANAGER_PATH,
KYLIN_APP_MANAGER_INTERFACE,
"LaunchAppWithArguments");
message << appid << args;
auto watcher = new QDBusPendingCallWatcher(QDBusConnection::sessionBus().asyncCall(message), this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [applicationName, args] (QDBusPendingCallWatcher *self) {
if (self) {
QDBusPendingReply reply = *self;
if (self->isError()) {
qWarning() << reply.error().message();
QProcess::startDetached(applicationName, args);
}
self->deleteLater();
}
});
}
void AppManager::changeFavoriteState(const QString &appid, bool isFavorite)
{
BasicAppFilterModel::instance()->databaseInterface()->fixAppToFavorite(appid, isFavorite ? 1 : 0);
}
QStringList AppManager::parseDesktopFile(const QString &appid)
{
// TODO: try QSettings?
QSettings file(appid, QSettings::IniFormat);
file.beginGroup(QStringLiteral("Desktop Entry"));
QStringList stringList = file.value(QStringLiteral("Exec")).toString().split(" ");
file.endGroup();
if (stringList.isEmpty()) {
return {};
}
QStringList res;
res << stringList.takeFirst();
// TODO: freedesktop group
for (const auto &str : stringList) {
if (!str.startsWith("%")) {
res.append(str);
}
}
return res;
}
} // UkuiMenu
ukui-menu/src/utils/event-track.h 0000664 0001750 0001750 00000002742 15160463353 015755 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_MENU_EVENT_TRACK_H
#define UKUI_MENU_EVENT_TRACK_H
#include
#include
#include
namespace UkuiMenu {
class EventTrack : public QObject
{
Q_OBJECT
public:
static EventTrack *qmlAttachedProperties(QObject *object);
static EventTrack *instance();
explicit EventTrack(QObject *parent = nullptr);
Q_INVOKABLE void sendClickEvent(const QString& event, const QString& page, const QVariantMap &map = {});
Q_INVOKABLE void sendDefaultEvent(const QString& event, const QString& page, const QVariantMap &map = {});
Q_INVOKABLE void sendSearchEvent(const QString& event, const QString& page, const QString& content);
};
} // Sidebar
QML_DECLARE_TYPEINFO(UkuiMenu::EventTrack, QML_HAS_ATTACHED_PROPERTIES)
#endif //UKUI_MENU_EVENT_TRACK_H
ukui-menu/src/utils/user-info-item.h 0000664 0001750 0001750 00000003104 15160463365 016371 0 ustar feng feng #ifndef USERINFOITEM_H
#define USERINFOITEM_H
#include
#include
#include