feat(frontend): Rebuild frontend & implement plugins interface.

Description: 前端重构与插件接口实现

Log: 前端重构与插件接口实现
This commit is contained in:
zhangjiaping 2021-05-22 21:29:43 +08:00
parent 823130fa8b
commit c9079b067d
58 changed files with 6220 additions and 2 deletions

View File

View File

@ -0,0 +1,17 @@
include(stack-pages/stack-pages.pri)
include(flow-layout/flow-layout.pri)
include(list-labels/list-labels.pri)
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/settings-widget.h \
$$PWD/create-index-ask-dialog.h \
$$PWD/stacked-widget.h \
$$PWD/input-box.h \
SOURCES += \
$$PWD/settings-widget.cpp \
$$PWD/create-index-ask-dialog.cpp \
$$PWD/stacked-widget.cpp \
$$PWD/input-box.cpp \

View File

@ -0,0 +1,150 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "create-index-ask-dialog.h"
#include <QPainterPath>
#define MAIN_SIZE QSize(380, 202)
#define MAIN_SPACING 0
#define MAIN_MARGINS 0,0,0,0
#define TITLE_MARGINS 8,8,8,8
#define TITLE_HEIGHT 40
#define ICON_SIZE QSize(24, 24)
#define TIP_LABEL_HEIGHT 64
#define CLOSE_BTN_SIZE QSize(24, 24)
#define CHECK_BOX_MARGINS 0,0,0,0
#define BTN_FRAME_MARGINS 0,0,0,0
#define CONTENT_MARGINS 32,0,32,24
using namespace Zeeker;
CreateIndexAskDialog::CreateIndexAskDialog(QWidget *parent) : QDialog(parent) {
// this->setWindowIcon(QIcon::fromTheme("kylin-search"));
this->setWindowTitle(tr("ukui-search"));
initUi();
}
void CreateIndexAskDialog::initUi() {
this->setFixedSize(MAIN_SIZE);
m_mainLyt = new QVBoxLayout(this);
this->setLayout(m_mainLyt);
m_mainLyt->setContentsMargins(MAIN_MARGINS);
m_mainLyt->setSpacing(MAIN_SPACING);
//标题栏
m_titleFrame = new QFrame(this);
m_titleFrame->setFixedHeight(TITLE_HEIGHT);
m_titleLyt = new QHBoxLayout(m_titleFrame);
m_titleLyt->setContentsMargins(TITLE_MARGINS);
m_titleFrame->setLayout(m_titleLyt);
m_iconLabel = new QLabel(m_titleFrame);
m_iconLabel->setFixedSize(ICON_SIZE);
m_iconLabel->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(24, 24)));
//主题改变时,更新自定义标题栏的图标
connect(qApp, &QApplication::paletteChanged, this, [ = ]() {
m_iconLabel->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(24, 24)));
});
m_titleLabel = new QLabel(m_titleFrame);
m_titleLabel->setText(tr("Search"));
m_closeBtn = new QPushButton(m_titleFrame);
m_closeBtn->setFixedSize(CLOSE_BTN_SIZE);
m_closeBtn->setIcon(QIcon::fromTheme("window-close-symbolic"));
m_closeBtn->setProperty("isWindowButton", 0x02);
m_closeBtn->setProperty("useIconHighlightEffect", 0x08);
m_closeBtn->setFlat(true);
connect(m_closeBtn, &QPushButton::clicked, this, [ = ]() {
this->hide();
Q_EMIT this->closed();
});
m_titleLyt->addWidget(m_iconLabel);
m_titleLyt->addWidget(m_titleLabel);
m_titleLyt->addStretch();
m_titleLyt->addWidget(m_closeBtn);
m_mainLyt->addWidget(m_titleFrame);
//内容区域
m_contentFrame = new QFrame(this);
m_contentLyt = new QVBoxLayout(m_contentFrame);
m_contentFrame->setLayout(m_contentLyt);
m_contentLyt->setContentsMargins(CONTENT_MARGINS);
m_tipLabel = new QLabel(m_contentFrame);
m_tipLabel->setText(tr("Creating index can help you getting results quickly, whether to create or not?"));
m_tipLabel->setWordWrap(true);
m_tipLabel->setAlignment(Qt::AlignVCenter);
m_tipLabel->setMinimumHeight(TIP_LABEL_HEIGHT);
m_contentLyt->addWidget(m_tipLabel);
m_checkFrame = new QFrame(m_contentFrame);
m_checkLyt = new QHBoxLayout(m_checkFrame);
m_checkLyt->setContentsMargins(CHECK_BOX_MARGINS);
m_checkFrame->setLayout(m_checkLyt);
m_checkBox = new QCheckBox(m_checkFrame);
m_checkBox->setText(tr("Don't remind"));
m_checkLyt->addWidget(m_checkBox);
m_checkLyt->addStretch();
m_contentLyt->addWidget(m_checkFrame);
m_contentLyt->addStretch();
m_btnFrame = new QFrame(m_contentFrame);
m_btnLyt = new QHBoxLayout(m_btnFrame);
m_btnFrame->setLayout(m_btnLyt);
m_btnLyt->setContentsMargins(BTN_FRAME_MARGINS);
m_cancelBtn = new QPushButton(m_btnFrame);
m_cancelBtn->setText(tr("No"));
m_confirmBtn = new QPushButton(m_btnFrame);
m_confirmBtn->setText(tr("Yes"));
connect(m_cancelBtn, &QPushButton::clicked, this, [ = ]() {
Q_EMIT this->btnClicked(false, m_checkBox->isChecked());
this->hide();
Q_EMIT this->closed();
});
connect(m_confirmBtn, &QPushButton::clicked, this, [ = ]() {
Q_EMIT this->btnClicked(true, m_checkBox->isChecked());
this->hide();
Q_EMIT this->closed();
});
m_btnLyt->addStretch();
m_btnLyt->addWidget(m_cancelBtn);
m_btnLyt->addWidget(m_confirmBtn);
m_contentLyt->addWidget(m_btnFrame);
m_mainLyt->addWidget(m_contentFrame);
#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0))
m_titleFrame->hide();
this->setFixedSize(380, 162);
#endif
}
/**
* @brief CreateIndexAskDialog::paintEvent
*/
void CreateIndexAskDialog::paintEvent(QPaintEvent *event) {
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
QPainterPath rectPath;
rectPath.addRect(this->rect());
p.save();
p.fillPath(rectPath, palette().color(QPalette::Base));
p.restore();
return QDialog::paintEvent(event);
}

View File

@ -0,0 +1,75 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef CREATEINDEXASKDIALOG_H
#define CREATEINDEXASKDIALOG_H
#include <QDialog>
#include <QFrame>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QCheckBox>
#include <QLabel>
#include <QPushButton>
#include <QStyleOption>
#include <QApplication>
#include <QPainter>
namespace Zeeker {
class CreateIndexAskDialog : public QDialog {
Q_OBJECT
public:
CreateIndexAskDialog(QWidget *parent = nullptr);
~CreateIndexAskDialog() = default;
private:
void initUi();
QVBoxLayout * m_mainLyt = nullptr;
//标题栏
QFrame * m_titleFrame = nullptr;
QHBoxLayout * m_titleLyt = nullptr;
QLabel * m_iconLabel = nullptr;
QLabel * m_titleLabel = nullptr;
QPushButton * m_closeBtn = nullptr;
//内容区域
QFrame * m_contentFrame = nullptr;
QVBoxLayout * m_contentLyt = nullptr;
QLabel * m_tipLabel = nullptr; //提示语
QFrame * m_checkFrame = nullptr; //"不再提示"选项框区域
QHBoxLayout * m_checkLyt = nullptr;
QCheckBox * m_checkBox = nullptr;
QFrame * m_btnFrame = nullptr; //底部按钮区域
QHBoxLayout * m_btnLyt = nullptr;
QPushButton * m_cancelBtn = nullptr;
QPushButton * m_confirmBtn = nullptr;
void paintEvent(QPaintEvent *);
Q_SIGNALS:
void closed();
void btnClicked(const bool&, const bool&);
};
}
#endif // CREATEINDEXASKDIALOG_H

View File

@ -0,0 +1,162 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2019 Tianjin KYLIN Information Technology 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "flow-layout.h"
#include <QWidget>
#include <QDebug>
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) :
QLayout(parent),
m_hSpace(hSpacing),
m_vSpace(vSpacing)
{
setContentsMargins(margin, margin, margin, margin);
}
FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
: m_hSpace(hSpacing),
m_vSpace(vSpacing)
{
setContentsMargins(margin, margin, margin, margin);
}
FlowLayout::~FlowLayout(){
QLayoutItem * item;
while ((item = takeAt(0))) {
}
}
void FlowLayout::addItem(QLayoutItem *item){
itemList.append(item);
}
int FlowLayout::horizontalSpacing() const{
if (m_hSpace >= 0) {
return m_hSpace;
} else {
return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
}
}
int FlowLayout::verticalSpacing() const{
if (m_vSpace >= 0) {
return m_vSpace;
} else {
return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
}
}
int FlowLayout::count() const{
return itemList.size();
}
QLayoutItem * FlowLayout::itemAt(int index) const{
return itemList.value(index);
}
QLayoutItem * FlowLayout::takeAt(int index){
if (index >= 0 && index < itemList.size())
return itemList.takeAt(index);
else
return 0;
}
Qt::Orientations FlowLayout::expandingDirections() const{
return 0;
}
bool FlowLayout::hasHeightForWidth() const{
return true;
}
int FlowLayout::heightForWidth(int width) const{
int height = doLayout(QRect(0, 0, width, 0), true);
return height;
}
void FlowLayout::setGeometry(const QRect &rect){
QLayout::setGeometry(rect);
doLayout(rect, false);
}
QSize FlowLayout::sizeHint() const{
return minimumSize();
}
QSize FlowLayout::minimumSize() const{
QSize size;
QLayoutItem *item;
Q_FOREACH (item, itemList)
size = size.expandedTo(item->minimumSize());
size += QSize(2*margin(), 2*margin());
return size;
}
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const{
int left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
int x = effectiveRect.x();
int y = effectiveRect.y();
int lineHeight = 0;
QLayoutItem *item;
Q_FOREACH (item, itemList) {
QWidget *wid = item->widget();
int spaceX = horizontalSpacing();
if (spaceX == -1)
spaceX = wid->style()->layoutSpacing(
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
int spaceY = verticalSpacing();
if (spaceY == -1)
spaceY = wid->style()->layoutSpacing(
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
int nextX = x + item->sizeHint().width() + spaceX;
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
x = effectiveRect.x();
y = y + lineHeight + spaceY;
nextX = x + item->sizeHint().width() + spaceX;
lineHeight = 0;
}
if (!testOnly)
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
x = nextX;
lineHeight = qMax(lineHeight, item->sizeHint().height());
}
return y + lineHeight - rect.y() + bottom;
}
int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const{
QObject *parent = this->parent();
if (!parent) {
return -1;
} else if (parent->isWidgetType()) {
QWidget *pw = static_cast<QWidget *>(parent);
return pw->style()->pixelMetric(pm, 0, pw);
} else {
return static_cast<QLayout *>(parent)->spacing();
}
}

View File

@ -0,0 +1,61 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2019 Tianjin KYLIN Information Technology 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef FLOWLAYOUT_H
#define FLOWLAYOUT_H
#include <QLayout>
#include <QRect>
#include <QStyle>
class FlowLayout : public QLayout
{
public:
explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
~FlowLayout();
public:
void addItem(QLayoutItem *item) Q_DECL_OVERRIDE;
int horizontalSpacing() const;
int verticalSpacing() const;
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
bool hasHeightForWidth() const Q_DECL_OVERRIDE;
int heightForWidth(int) const Q_DECL_OVERRIDE;
int count() const Q_DECL_OVERRIDE;
QLayoutItem *itemAt(int index) const Q_DECL_OVERRIDE;
QSize minimumSize() const Q_DECL_OVERRIDE;
void setGeometry(const QRect &rect) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
QLayoutItem *takeAt(int index) Q_DECL_OVERRIDE;
private:
int doLayout(const QRect &rect, bool testOnly) const;
int smartSpacing(QStyle::PixelMetric pm) const;
private:
QList<QLayoutItem *> itemList;
int m_hSpace;
int m_vSpace;
};
#endif // FLOWLAYOUT_H

View File

@ -0,0 +1,5 @@
SOURCES += \
$$PWD/flow-layout.cpp \
HEADERS += \
$$PWD/flow-layout.h \

View File

@ -0,0 +1,265 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "input-box.h"
using namespace Zeeker;
/**
* @brief ukui-search顶部搜索界面
*/
SeachBarWidget::SeachBarWidget(QWidget *parent): QWidget(parent) {
}
SeachBarWidget::~SeachBarWidget() {
}
/**
* @brief ukui-search ui
*/
SeachBar::SeachBar() {
setFocusPolicy(Qt::NoFocus);
}
SearchBarWidgetLayout::SearchBarWidgetLayout() {
}
SearchBarWidgetLayout::~SearchBarWidgetLayout() {
}
SeachBar::~SeachBar() {
}
/**
* @brief
*/
SearchBarHLayout::SearchBarHLayout(QWidget *parent): QHBoxLayout(parent) {
initUI();
m_timer = new QTimer;
connect(m_timer, &QTimer::timeout, this, [ = ]() {
m_timer->stop();
Q_EMIT this->requestSearchKeyword(m_queryLineEdit->text());
});
connect(m_queryLineEdit, &SearchLineEdit::textChanged, this, [ = ](QString text) {
if(m_isEmpty) {
m_isEmpty = false;
Q_EMIT this->requestSearchKeyword(text);
} else {
if(text == "") {
m_isEmpty = true;
m_timer->stop();
Q_EMIT this->requestSearchKeyword(m_queryLineEdit->text());
return;
}
m_timer->stop();
m_timer->start(0.1 * 1000);
}
});
}
SearchBarHLayout::~SearchBarHLayout() {
if(m_timer) {
delete m_timer;
m_timer = NULL;
}
if(m_queryLineEdit) {
delete m_queryLineEdit;
m_queryLineEdit = nullptr;
}
}
/**
* @brief ui
*/
void SearchBarHLayout::initUI() {
m_queryLineEdit = new SearchLineEdit();
m_queryLineEdit->installEventFilter(this);
m_queryLineEdit->setTextMargins(30, 1, 0, 1);
this->setContentsMargins(0, 0, 0, 0);
this->setAlignment(m_queryLineEdit, Qt::AlignCenter);
this->addWidget(m_queryLineEdit);
m_queryWidget = new QWidget(m_queryLineEdit);
m_queryWidget->setFocusPolicy(Qt::NoFocus);
QHBoxLayout* queryWidLayout = new QHBoxLayout;
queryWidLayout->setContentsMargins(8, 4, 0, 0);
queryWidLayout->setAlignment(Qt::AlignJustify);
queryWidLayout->setSpacing(5);
m_queryWidget->setLayout(queryWidLayout);
QPixmap pixmap(QIcon::fromTheme("system-search-symbolic").pixmap(QSize(20, 20)));
m_queryIcon = new QLabel;
m_queryIcon->setFixedSize(pixmap.size());
m_queryIcon->setPixmap(pixmap);
m_queryText = new QLabel;
m_queryText->setText(tr("Search"));
m_queryText->setEnabled(false);
m_queryText->setContentsMargins(0, 0, 0, 4);
m_queryText->adjustSize();
queryWidLayout->addWidget(m_queryIcon);
queryWidLayout->addWidget(m_queryText);
m_queryWidget->setGeometry(QRect((m_queryLineEdit->width() - (m_queryIcon->width() + m_queryText->width() + 15)) / 2 - 10, 0,
m_queryIcon->width() + m_queryText->width() + 20, 35)); //设置图标初始位置
m_animation = new QPropertyAnimation(m_queryWidget, "geometry");
m_animation->setDuration(100); //动画时长
connect(m_animation, &QPropertyAnimation::finished, this, [ = ]() {
if(m_isSearching) {
m_queryWidget->layout()->removeWidget(m_queryText);
m_queryText->setParent(nullptr);
} else {
m_queryWidget->layout()->addWidget(m_queryText);
}
});
}
void SearchBarHLayout::effectiveSearchRecord() {
m_queryLineEdit->record();
}
void SearchBarHLayout::focusIn() {
m_queryLineEdit->setFocus();
}
void SearchBarHLayout::focusOut() {
m_queryLineEdit->clearFocus();
if(! m_queryText->parent()) {
m_queryWidget->layout()->addWidget(m_queryText);
m_queryText->adjustSize();
}
m_queryWidget->setGeometry(QRect((m_queryLineEdit->width() - (m_queryIcon->width() + m_queryText->width() + 15)) / 2 - 10, 0,
m_queryIcon->width() + m_queryText->width() + 20, 35)); //使图标回到初始位置
}
void SearchBarHLayout::reSearch()
{
Q_EMIT this->requestSearchKeyword(m_queryLineEdit->text());
}
void SearchBarHLayout::clearText() {
m_queryLineEdit->setText("");
}
QString SearchBarHLayout::text() {
return m_queryLineEdit->text();
}
bool SearchBarHLayout::eventFilter(QObject *watched, QEvent *event) {
if(watched == m_queryLineEdit) {
if(event->type() == QEvent::FocusIn) {
if(m_queryLineEdit->text().isEmpty()) {
m_animation->stop();
m_animation->setStartValue(m_queryWidget->geometry());
m_animation->setEndValue(QRect(0, 0, m_queryIcon->width() + 10, 35));
m_animation->setEasingCurve(QEasingCurve::OutQuad);
m_animation->start();
}
m_isSearching = true;
} else if(event->type() == QEvent::FocusOut) {
if(m_queryLineEdit->text().isEmpty()) {
if(m_isSearching) {
m_animation->stop();
m_queryText->adjustSize();
m_animation->setStartValue(QRect(0, 0, m_queryIcon->width() + 5, 35));
m_animation->setEndValue(QRect((m_queryLineEdit->width() - (m_queryIcon->width() + m_queryText->width() + 10)) / 2, 0,
m_queryIcon->width() + m_queryText->width() + 20, 35));
m_animation->setEasingCurve(QEasingCurve::InQuad);
m_animation->start();
}
}
m_isSearching = false;
}
}
return QObject::eventFilter(watched, event);
}
/**
* @brief UKuiSearchLineEdit
*/
SearchLineEdit::SearchLineEdit() {
this->setFocusPolicy(Qt::ClickFocus);
this->installEventFilter(this);
// this->setContextMenuPolicy(Qt::NoContextMenu);
this->setMaxLength(100);
m_completer = new QCompleter(this);
m_model = new QStringListModel(this);
m_model->setStringList(GlobalSettings::getInstance()->getSearchRecord());
m_completer->setModel(m_model);
m_completer->setCompletionMode(QCompleter::InlineCompletion);
//TODO make a popup window to show the completer.
// QListView *popView = new QListView(this);
// popView->setFocusPolicy(Qt::NoFocus);
// popView->setProperty("useCustomShadow", true);
// popView->setProperty("customShadowDarkness", 0.5);
// popView->setProperty("customShadowWidth", 20);
// popView->setProperty("customShadowRadius", QVector4D(6, 6, 6, 6));
// popView->setProperty("customShadowMargins", QVector4D(20, 20, 20, 20));
// popView->setAttribute(Qt::WA_TranslucentBackground);
// m_completer->setPopup(popView);
m_completer->setMaxVisibleItems(14);
setCompleter(m_completer);
//这是搜索框图标,要改
// QAction *searchAction = new QAction(this);
// searchAction->setIcon(QIcon(":/res/icons/edit-find-symbolic.svg"));
// this->addAction(searchAction,QLineEdit::LeadingPosition);
/*发送输入框文字改变的dbus*/
QDBusConnection::sessionBus().unregisterService("org.ukui.search.service");
QDBusConnection::sessionBus().registerService("org.ukui.search.service");
QDBusConnection::sessionBus().registerObject("/lineEdit/textChanged", this, QDBusConnection :: ExportAllSlots | QDBusConnection :: ExportAllSignals);
connect(this, &QLineEdit::textChanged, this, &SearchLineEdit::lineEditTextChanged);
connect(this, &QLineEdit::textChanged, this, [ = ]() {
m_isRecorded = false;
});
}
void SearchLineEdit::record() {
if(m_isRecorded == true || text().size() <= 1 || text().isEmpty())
return;
GlobalSettings::getInstance()->setSearchRecord(text(), QDateTime::currentDateTime());
m_isRecorded = true;
m_model->setStringList(GlobalSettings::getInstance()->getSearchRecord());
}
SearchLineEdit::~SearchLineEdit() {
}
/**
* @brief lineEditTextChange textChanged信号dbus信号给其他程序
* @param arg
*
*
* QDBusConnection::sessionBus().connect(QString(), QString("/lineEdit/textChanged"), "org.ukui.search.inputbox", "InputBoxTextChanged", this, SLOT(client_get(QString)));
* client_get(void) 
*/
void SearchLineEdit::lineEditTextChanged(QString arg) {
QDBusMessage message = QDBusMessage::createSignal("/lineEdit/textChanged", "org.ukui.search.inputbox", "InputBoxTextChanged");
message << arg;
QDBusConnection::sessionBus().send(message);
}

View File

@ -0,0 +1,119 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef INPUTBOX_H
#define INPUTBOX_H
#include <QWidget>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QtDBus/QtDBus>
#include <QPainter>
#include <QAction>
#include <QTimer>
#include <QStringListModel>
#include <QCompleter>
#include <QAbstractItemView>
#include <QVector4D>
#include <QListView>
#include "global-settings.h"
namespace Zeeker {
class SearchLineEdit;
class SeachBarWidget: public QWidget {
public:
SeachBarWidget(QWidget *parent = nullptr);
~SeachBarWidget();
};
class SeachBar: public QWidget {
public:
SeachBar();
~SeachBar();
private:
// QLineEdit *m_queryLineEdit=nullptr;
};
class SearchBarHLayout : public QHBoxLayout {
Q_OBJECT
public:
SearchBarHLayout(QWidget *parent = nullptr);
~SearchBarHLayout();
void clearText();
QString text();
void focusIn();
void focusOut();
void reSearch();
protected:
bool eventFilter(QObject *watched, QEvent *event);
private:
void initUI();
bool m_isEmpty = true;
QTimer * m_timer = nullptr;
SearchLineEdit * m_queryLineEdit = nullptr;
QPropertyAnimation * m_animation = nullptr;
QWidget * m_queryWidget = nullptr;
QLabel * m_queryIcon = nullptr;
QLabel * m_queryText = nullptr;
bool m_isSearching = false;
Q_SIGNALS:
void requestSearchKeyword(QString text);
public Q_SLOTS:
void effectiveSearchRecord();
};
class SearchBarWidgetLayout : public QHBoxLayout {
public:
SearchBarWidgetLayout();
~SearchBarWidgetLayout();
private:
void initUI();
};
class SearchLineEdit : public QLineEdit {
Q_OBJECT
/*
* ukui桌面环境应用通信的dbus
*
   */
Q_CLASSINFO("D-Bus Interface", "org.ukui.search.inputbox")
public:
SearchLineEdit();
void record();
~SearchLineEdit();
private Q_SLOTS:
void lineEditTextChanged(QString arg);
private:
QStringListModel *m_model = nullptr;
QCompleter *m_completer = nullptr;
bool m_isRecorded = false;
};
}
#endif //INPUTBOX_H

View File

@ -0,0 +1,9 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/show-more-label.h \
$$PWD/title-label.h \
SOURCES += \
$$PWD/show-more-label.cpp \
$$PWD/title-label.cpp \

View File

@ -0,0 +1,77 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "show-more-label.h"
#include <QEvent>
#include <QDebug>
using namespace Zeeker;
ShowMoreLabel::ShowMoreLabel(QWidget *parent) : QWidget(parent) {
initUi();
m_timer = new QTimer;
}
void ShowMoreLabel::resetLabel() {
m_isOpen = false;
m_textLabel->setText(tr("Show More..."));
}
/**
* @brief ShowMoreLabel::getExpanded
* @return true已展开false已收起
*/
bool ShowMoreLabel::getExpanded() {
return m_isOpen;
}
void ShowMoreLabel::initUi() {
QPalette pal = palette();
pal.setColor(QPalette::WindowText, QColor(55, 144, 250, 255));
m_layout = new QHBoxLayout(this);
m_layout->setContentsMargins(0, 0, 0, 6);
m_textLabel = new QLabel(this);
m_textLabel->setText(tr("Show More..."));
m_textLabel->setCursor(QCursor(Qt::PointingHandCursor));
m_textLabel->installEventFilter(this);
// m_loadingIconLabel = new QLabel(this); //使用图片显示加载状态时取消此label的注释
// m_loadingIconLabel->setFixedSize(18, 18);
// m_loadingIconLabel->hide();
m_layout->setAlignment(Qt::AlignRight);
m_layout->addWidget(m_textLabel);
m_textLabel->setPalette(pal);
// m_layout->addWidget(m_loadingIconLabel);
}
bool ShowMoreLabel::eventFilter(QObject *watched, QEvent *event) {
if(watched == m_textLabel) {
if(event->type() == QEvent::MouseButtonPress) {
if(! m_timer->isActive()) {
if(!m_isOpen) {
m_isOpen = true;
Q_EMIT this->showMoreClicked();
} else {
m_isOpen = false;
Q_EMIT this->retractClicked();
}
}
}
}
return QWidget::eventFilter(watched, event);
}

View File

@ -0,0 +1,59 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef SHOWMORELABEL_H
#define SHOWMORELABEL_H
#include <QWidget>
#include <QLabel>
#include <QHBoxLayout>
#include <QTimer>
namespace Zeeker {
class ShowMoreLabel : public QWidget {
Q_OBJECT
public:
explicit ShowMoreLabel(QWidget *parent = nullptr);
~ShowMoreLabel() = default;
void resetLabel();
bool getExpanded();
protected:
bool eventFilter(QObject *, QEvent *);
private:
QHBoxLayout * m_layout = nullptr;
QLabel * m_textLabel = nullptr;
QLabel * m_loadingIconLabel = nullptr;
QTimer * m_timer = nullptr;
bool m_isOpen = false;
int m_currentState = 0;
void initUi();
Q_SIGNALS:
void showMoreClicked();
void retractClicked();
public Q_SLOTS:
};
}
#endif // SHOWMORELABEL_H

View File

@ -0,0 +1,50 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "title-label.h"
#include <QPainter>
#include <QStyleOption>
using namespace Zeeker;
TitleLabel::TitleLabel(QWidget * parent) : QLabel(parent) {
this->setContentsMargins(8, 0, 0, 0);
this->setFixedHeight(24);
}
TitleLabel::~TitleLabel() {
}
void TitleLabel::paintEvent(QPaintEvent * event) {
Q_UNUSED(event)
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QRect rect = this->rect();
p.setRenderHint(QPainter::Antialiasing); // 反锯齿;
p.setBrush(opt.palette.color(QPalette::Text));
p.setOpacity(0.04);
p.setPen(Qt::NoPen);
p.drawRoundedRect(rect, 0, 0);
return QLabel::paintEvent(event);
}

View File

@ -0,0 +1,37 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef TITLELABEL_H
#define TITLELABEL_H
#include <QLabel>
namespace Zeeker {
class TitleLabel : public QLabel {
public:
TitleLabel(QWidget * parent = nullptr);
~TitleLabel();
protected:
void paintEvent(QPaintEvent *);
};
}
#endif // TITLELABEL_H

View File

@ -0,0 +1,594 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "settings-widget.h"
#include <QPainter>
#include <QPainterPath>
#include <QFileDialog>
#include <QDir>
#include <QDebug>
#include <QMessageBox>
#include "global-settings.h"
#include "file-utils.h"
using namespace Zeeker;
extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed);
SettingsWidget::SettingsWidget(QWidget *parent) : QWidget(parent) {
// this->setWindowIcon(QIcon::fromTheme("kylin-search"));
this->setWindowTitle(tr("ukui-search-settings"));
// this->setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
// this->setAttribute(Qt::WA_TranslucentBackground);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
m_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
m_hints.functions = MWM_FUNC_ALL;
m_hints.decorations = MWM_DECOR_BORDER;
XAtomHelper::getInstance()->setWindowMotifHint(winId(), m_hints);
#endif
initUi();
refreshIndexState();
setupBlackList(GlobalSettings::getInstance()->getBlockDirs());
resetWebEngine();
}
SettingsWidget::~SettingsWidget() {
}
/**
* @brief SettingsWidget::initUi UI
*/
void SettingsWidget::initUi() {
QPalette pal = palette();
pal.setColor(QPalette::Window, QColor(0, 0, 0, 0));
// this->setFixedWidth(528);
// this->setMinimumHeight(460);
// this->setMaximumHeight(680);
m_mainLyt = new QVBoxLayout(this);
m_mainLyt->setContentsMargins(16, 8, 16, 24);
this->setLayout(m_mainLyt);
//标题栏
m_titleFrame = new QFrame(this);
m_titleFrame->setFixedHeight(40);
m_titleLyt = new QHBoxLayout(m_titleFrame);
m_titleLyt->setContentsMargins(0, 0, 0, 0);
m_titleFrame->setLayout(m_titleLyt);
m_titleIcon = new QLabel(m_titleFrame);
m_titleIcon->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(24, 24)));
//主题改变时,更新自定义标题栏的图标
connect(qApp, &QApplication::paletteChanged, this, [ = ]() {
m_titleIcon->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(24, 24)));
});
m_titleLabel = new QLabel(m_titleFrame);
m_titleLabel->setText(tr("Search"));
m_closeBtn = new QPushButton(m_titleFrame);
m_closeBtn->setFixedSize(24, 24);
// m_closeBtn->setIcon(QIcon(":/res/icons/close.svg"));
m_closeBtn->setIcon(QIcon::fromTheme("window-close-symbolic"));
m_closeBtn->setProperty("isWindowButton", 0x02);
m_closeBtn->setProperty("useIconHighlightEffect", 0x08);
m_closeBtn->setFlat(true);
connect(m_closeBtn, &QPushButton::clicked, this, [ = ]() {
Q_EMIT this->settingWidgetClosed();
m_timer->stop();
this->close();
});
m_titleLyt->addWidget(m_titleIcon);
m_titleLyt->addWidget(m_titleLabel);
m_titleLyt->addStretch();
m_titleLyt->addWidget(m_closeBtn);
m_mainLyt->addWidget(m_titleFrame);
m_contentFrame = new QFrame(this);
m_contentLyt = new QVBoxLayout(m_contentFrame);
m_contentFrame->setLayout(m_contentLyt);
m_contentLyt->setContentsMargins(8, 0, 8, 0);
m_mainLyt->addWidget(m_contentFrame);
//设置
m_settingLabel = new QLabel(m_contentFrame);
m_settingLabel->setText(tr("<h2>Settings</h2>"));
m_contentLyt->addWidget(m_settingLabel);
//文件索引
m_indexTitleLabel = new QLabel(m_contentFrame);
m_indexTitleLabel->setText(tr("<h3>Index State</h3>"));
m_indexStateLabel = new QLabel(m_contentFrame);
m_indexStateLabel->setText(tr("..."));
m_indexNumLabel = new QLabel(m_contentFrame);
m_indexNumLabel->setText(tr("..."));
m_contentLyt->addWidget(m_indexTitleLabel);
m_contentLyt->addWidget(m_indexStateLabel);
// m_mainLyt->addWidget(m_indexNumLabel);
m_indexNumLabel->hide();
//文件索引设置(黑名单)
m_indexSettingLabel = new QLabel(m_contentFrame);
m_indexSettingLabel->setText(tr("<h3>File Index Settings</h3>"));
m_indexDescLabel = new QLabel(m_contentFrame);
m_indexDescLabel->setText(tr("Following folders will not be searched. You can set it by adding and removing folders."));
m_indexDescLabel->setWordWrap(true);
m_indexBtnFrame = new QFrame(m_contentFrame);
m_indexBtnLyt = new QHBoxLayout(m_indexBtnFrame);
m_indexBtnLyt->setContentsMargins(0, 0, 0, 0);
m_indexBtnFrame->setLayout(m_indexBtnLyt);
m_addDirBtn = new QPushButton(m_indexBtnFrame);
m_addDirBtn->setFixedHeight(32);
m_addDirBtn->setMinimumWidth(164);
m_addDirBtn->setText(tr("Add ignored folders"));
connect(m_addDirBtn, &QPushButton::clicked, this, &SettingsWidget::onBtnAddClicked);
m_indexBtnLyt->addWidget(m_addDirBtn);
m_indexBtnLyt->addStretch();
m_dirListArea = new QScrollArea(m_contentFrame);
m_dirListArea->setPalette(pal);
m_dirListArea->setFrameShape(QFrame::Shape::NoFrame);
m_dirListWidget = new QWidget(m_contentFrame);
m_dirListLyt = new QVBoxLayout(m_dirListWidget);
m_dirListLyt->setContentsMargins(0, 0, 0, 0);
m_dirListLyt->setSpacing(0);
m_dirListWidget->setLayout(m_dirListLyt);
m_dirListArea->setWidget(m_dirListWidget);
m_dirListArea->setWidgetResizable(m_contentFrame);
m_contentLyt->addWidget(m_indexSettingLabel);
m_contentLyt->addWidget(m_indexDescLabel);
m_contentLyt->addWidget(m_indexBtnFrame);
m_contentLyt->addWidget(m_dirListArea);
//搜索引擎设置
m_searchEngineLabel = new QLabel(m_contentFrame);
m_searchEngineLabel->setText(tr("<h3>Search Engine Settings</h3>"));
m_engineDescLabel = new QLabel(m_contentFrame);
m_engineDescLabel->setText(tr("Please select search engine you preferred."));
m_engineDescLabel->setWordWrap(true);
m_engineBtnGroup = new QButtonGroup(m_contentFrame);
m_baiduBtn = new QRadioButton(m_contentFrame);
m_sougouBtn = new QRadioButton(m_contentFrame);
m_360Btn = new QRadioButton(m_contentFrame);
m_baiduBtn->setFixedSize(16, 16);
m_sougouBtn->setFixedSize(16, 16);
m_360Btn->setFixedSize(16, 16);
m_radioBtnFrame = new QFrame(m_contentFrame);
m_radioBtnLyt = new QHBoxLayout(m_radioBtnFrame);
m_radioBtnFrame->setLayout(m_radioBtnLyt);
m_baiduLabel = new QLabel();
m_baiduLabel->setText(tr("baidu"));
m_sougouLabel = new QLabel();
m_sougouLabel->setText(tr("sougou"));
m_360Label = new QLabel();
m_360Label->setText(tr("360"));
m_radioBtnLyt->setContentsMargins(0, 0, 0, 0);
m_radioBtnLyt->addWidget(m_baiduBtn);
m_radioBtnLyt->addWidget(m_baiduLabel);
m_radioBtnLyt->addWidget(m_sougouBtn);
m_radioBtnLyt->addWidget(m_sougouLabel);
m_radioBtnLyt->addWidget(m_360Btn);
m_radioBtnLyt->addWidget(m_360Label);
m_radioBtnLyt->addStretch();
m_engineBtnGroup->setExclusive(true);
m_engineBtnGroup->addButton(m_baiduBtn);
m_engineBtnGroup->addButton(m_sougouBtn);
m_engineBtnGroup->addButton(m_360Btn);
// m_engineBtnGroup->setId(m_baiduBtn, WebEngine::Baidu);
// m_engineBtnGroup->setId(m_sougouBtn, WebEngine::Sougou);
// m_engineBtnGroup->setId(m_360Btn, WebEngine::_360);
// connect(m_engineBtnGroup, QOverload<int>::of(&QButtonGroup::buttonClicked), [ = ] (int id) {
// setWebEngine(id);
// });
connect(m_baiduBtn, &QRadioButton::clicked, [ = ](bool checked) {
if(checked) setWebEngine("baidu");
});
connect(m_sougouBtn, &QRadioButton::clicked, [ = ](bool checked) {
if(checked) setWebEngine("sougou");
});
connect(m_360Btn, &QRadioButton::clicked, [ = ](bool checked) {
if(checked) setWebEngine("360");
});
m_contentLyt->addWidget(m_searchEngineLabel);
m_contentLyt->addWidget(m_engineDescLabel);
m_contentLyt->addWidget(m_radioBtnFrame);
//取消与确认按钮 (隐藏)
// m_bottomBtnFrame = new QFrame(this);
// m_bottomBtnLyt = new QHBoxLayout(m_bottomBtnFrame);
// m_bottomBtnFrame->setLayout(m_bottomBtnLyt);
// m_bottomBtnLyt->setSpacing(20);
// m_cancelBtn = new QPushButton(m_bottomBtnFrame);
// m_cancelBtn->setText(tr("Cancel"));
// m_cancelBtn->setFixedSize(80, 32);
// connect(m_cancelBtn, &QPushButton::clicked, this, &SettingsWidget::onBtnCancelClicked);
// m_confirmBtn = new QPushButton(m_bottomBtnFrame);
// m_confirmBtn->setText(tr("Confirm"));
// m_confirmBtn->setFixedSize(80, 32);
// connect(m_confirmBtn, &QPushButton::clicked, this, &SettingsWidget::onBtnConfirmClicked);
// m_bottomBtnLyt->addStretch();
// m_bottomBtnLyt->addWidget(m_cancelBtn);
// m_bottomBtnLyt->addWidget(m_confirmBtn);
// m_mainLyt->addWidget(m_bottomBtnFrame);
m_contentLyt->addStretch();
#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0))
this->m_titleFrame->hide();
setAttribute(Qt::WA_DeleteOnClose);
#endif
}
/**
* @brief SettingsWidget::setupBlackList
* @param list
*/
void SettingsWidget::setupBlackList(const QStringList& list) {
clearLayout(m_dirListLyt);
m_blockdirs = 0;
Q_FOREACH(QString path, list) {
FolderListItem * item = new FolderListItem(m_dirListWidget, path);
m_dirListLyt->addWidget(item);
item->setMaximumWidth(this->width() - 52);
connect(item, &FolderListItem::onDelBtnClicked, this, &SettingsWidget::onBtnDelClicked);
m_blockdirs ++;
}
this->resize();
m_dirListWidget->setFixedWidth(this->width() - 68);
// m_dirListLyt->addStretch();
}
/**
* @brief SettingsWidget::clearLayout
* @param layout
*/
void SettingsWidget::clearLayout(QLayout * layout) {
if(! layout) return;
QLayoutItem * child;
while((child = layout->takeAt(0)) != 0) {
if(child->widget()) {
child->widget()->setParent(NULL);
}
delete child;
}
child = NULL;
}
/**
* @brief SettingsWidget::refreshIndexState
*/
void SettingsWidget::refreshIndexState() {
// qDebug()<<"FileUtils::_index_status: "<<FileUtils::_index_status;
if(FileUtils::_index_status != 0) {
this->setIndexState(true);
} else {
this->setIndexState(false);
}
m_indexNumLabel->setText(QString("%1/%2").arg(QString::number(SearchManager::getCurrentIndexCount())).arg(QString::number(FileUtils::_max_index_count)));
m_timer = new QTimer;
connect(m_timer, &QTimer::timeout, this, [ = ]() {
qDebug() << "FileUtils::_index_status: " << FileUtils::_index_status;
if(FileUtils::_index_status != 0) {
this->setIndexState(true);
} else {
this->setIndexState(false);
}
m_indexNumLabel->setText(QString("%1/%2").arg(QString::number(SearchManager::getCurrentIndexCount())).arg(QString::number(FileUtils::_max_index_count)));
});
m_timer->start(0.5 * 1000);
}
/**
* @brief SettingsWidget::onBtnDelClicked
* @param path
*/
void SettingsWidget::onBtnDelClicked(const QString& path) {
QMessageBox message(QMessageBox::Question, tr("Search"), tr("Whether to delete this directory?"));
QPushButton * buttonYes = message.addButton(tr("Yes"), QMessageBox::YesRole);
message.addButton(tr("No"), QMessageBox::NoRole);
message.exec();
if(message.clickedButton() != buttonYes) {
return;
}
int returnCode = 0;
if(GlobalSettings::getInstance()->setBlockDirs(path, returnCode, true)) {
qDebug() << "Remove block dir in onBtnDelClicked() successed.";
Q_FOREACH(FolderListItem * item, m_dirListWidget->findChildren<FolderListItem*>()) {
if(item->getPath() == path) {
item->deleteLater();
item = NULL;
m_blockdirs --;
this->resize();
return;
}
}
} else {
showWarningDialog(returnCode);
}
}
/**
* @brief SettingsWidget::resetWebEngine UI控件上
*/
void SettingsWidget::resetWebEngine() {
QString engine = GlobalSettings::getInstance()->getValue(WEB_ENGINE).toString();
m_engineBtnGroup->blockSignals(true);
if(!engine.isEmpty()) {
if(engine == "360") {
m_360Btn->setChecked(true);
} else if(engine == "sougou") {
m_sougouBtn->setChecked(true);
} else {
m_baiduBtn->setChecked(true);
}
} else {
m_baiduBtn->setChecked(true);
}
m_engineBtnGroup->blockSignals(false);
}
/**
* @brief SettingsWidget::setWebEngine
* @param engine
*/
void SettingsWidget::setWebEngine(const QString& engine) {
// GlobalSettings::getInstance()->setValue(WEB_ENGINE, engine);
Q_EMIT this->webEngineChanged(engine);
}
/**
* @brief setIndexState
* @param isCreatingIndex
*/
void SettingsWidget::setIndexState(bool isCreatingIndex) {
if(isCreatingIndex) {
m_indexStateLabel->setText(tr("Creating ..."));
return;
}
m_indexStateLabel->setText(tr("Done"));
}
/**
* @brief SettingsWidget::setIndexNum
* @param num
*/
void SettingsWidget::setIndexNum(int num) {
m_indexNumLabel->setText(QString(tr("Index Entry: %1")).arg(QString::number(num)));
}
/**
* @brief SettingsWidget::showWidget
*/
void SettingsWidget::showWidget() {
Qt::WindowFlags flags = this->windowFlags();
flags |= Qt::WindowStaysOnTopHint;
this->setWindowFlags(flags);
flags &= ~Qt::WindowStaysOnTopHint;
this->setWindowFlags(flags);
m_timer->start();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
XAtomHelper::getInstance()->setWindowMotifHint(winId(), m_hints);
#endif
this->show();
}
///**
// * @brief SettingsWidget::onBtnConfirmClicked 点击确认按钮的槽函数
// */
//void SettingsWidget::onBtnConfirmClicked() {
// Q_EMIT this->settingWidgetClosed();
// m_timer->stop();
// this->close();
//}
///**
// * @brief SettingsWidget::onBtnCancelClicked 点击取消按钮的槽函数
// */
//void SettingsWidget::onBtnCancelClicked() {
// Q_EMIT this->settingWidgetClosed();
// m_timer->stop();
// this->close();
//}
/**
* @brief SettingsWidget::onBtnAddClicked
*/
void SettingsWidget::onBtnAddClicked() {
QFileDialog * fileDialog = new QFileDialog(this);
// fileDialog->setFileMode(QFileDialog::Directory); //允许查看文件和文件夹,但只允许选择文件夹
fileDialog->setFileMode(QFileDialog::DirectoryOnly); //只允许查看文件夹
// fileDialog->setViewMode(QFileDialog::Detail);
fileDialog->setDirectory(QDir::homePath());
fileDialog->setNameFilter(tr("Directories"));
fileDialog->setWindowTitle(tr("select blocked folder"));
fileDialog->setLabelText(QFileDialog::Accept, tr("Select"));
fileDialog->setLabelText(QFileDialog::LookIn, tr("Position: "));
fileDialog->setLabelText(QFileDialog::FileName, tr("FileName: "));
fileDialog->setLabelText(QFileDialog::FileType, tr("FileType: "));
fileDialog->setLabelText(QFileDialog::Reject, tr("Cancel"));
if(fileDialog->exec() != QDialog::Accepted) {
fileDialog->deleteLater();
return;
}
QString selectedDir = 0;
int returnCode;
selectedDir = fileDialog->selectedFiles().first();
qDebug() << "Selected a folder in onBtnAddClicked(): " << selectedDir << ". ->settings-widget.cpp #238";
if(GlobalSettings::getInstance()->setBlockDirs(selectedDir, returnCode)) {
setupBlackList(GlobalSettings::getInstance()->getBlockDirs());
qDebug() << "Add block dir in onBtnAddClicked() successed. ->settings-widget.cpp #238";
} else {
showWarningDialog(returnCode);
}
}
/**
* @brief SettingsWidget::paintEvent
* @param event
*/
void SettingsWidget::paintEvent(QPaintEvent *event) {
Q_UNUSED(event)
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
QPainterPath rectPath;
rectPath.addRect(this->rect());
// 绘制一个背景
p.save();
p.fillPath(rectPath, palette().color(QPalette::Base));
p.restore();
}
/**
* @brief SettingsWidget::resize
*/
void SettingsWidget::resize() {
// if (m_blockdirs <= 1) {
// this->setFixedSize(528, 455);
// } else if (m_blockdirs <= 3) {
// this->setFixedSize(528, 425 + 30 * m_blockdirs);
// } else {
// this->setFixedSize(528, 515);
// }
if(m_blockdirs <= 4) {
m_dirListArea->setFixedHeight(32 * m_blockdirs + 4);
m_dirListWidget->setFixedHeight(32 * m_blockdirs);
} else {
m_dirListWidget->setFixedHeight(32 * m_blockdirs);
m_dirListArea->setFixedHeight(32 * 4 + 4);
}
this->setFixedSize(528, 410 + m_dirListArea->height());
}
/**
* @brief SettingsWidget::showWarningDialog
* @param errorCode
*/
void SettingsWidget::showWarningDialog(const int & errorCode) {
qWarning() << "Add block dir in onBtnAddClicked() failed. Code: " << errorCode << " ->settings-widget.cpp #238";
QString errorMessage;
switch(errorCode) {
case 1: {
errorMessage = tr("Choosen path is Empty!");
break;
}
case 2: {
errorMessage = tr("Choosen path is not in \"home\"!");
break;
}
case 3: {
errorMessage = tr("Its' parent folder has been blocked!");
break;
}
default: {
errorMessage = tr("Set blocked folder failed!");
break;
}
}
QMessageBox message(QMessageBox::Warning, tr("Search"), errorMessage);
message.addButton(tr("OK"), QMessageBox::AcceptRole);
message.exec();
}
FolderListItem::FolderListItem(QWidget *parent, const QString &path) : QWidget(parent) {
m_path = path;
initUi();
}
FolderListItem::~FolderListItem() {
}
/**
* @brief FolderListItem::initUi ui
*/
void FolderListItem::initUi() {
m_layout = new QVBoxLayout(this);
m_layout->setSpacing(0);
m_layout->setContentsMargins(0, 0, 0, 0);
m_widget = new QWidget(this);
m_widget->setObjectName("mWidget");
this->setFixedHeight(32);
m_layout->addWidget(m_widget);
m_widgetlayout = new QHBoxLayout(m_widget);
m_widgetlayout->setContentsMargins(8, 4, 8, 4);
m_widget->setLayout(m_widgetlayout);
m_iconLabel = new QLabel(m_widget);
m_pathLabel = new QLabel(m_widget);
m_delLabel = new QLabel(m_widget);
m_iconLabel->setPixmap(QIcon::fromTheme("inode-directory").pixmap(QSize(16, 16)));
m_pathLabel->setText(m_path);
m_delLabel->setText(tr("Delete the folder out of blacklist"));
QPalette pal = palette();
pal.setColor(QPalette::WindowText, QColor(55, 144, 250, 255));
m_delLabel->setPalette(pal);
m_delLabel->setCursor(QCursor(Qt::PointingHandCursor));
m_delLabel->installEventFilter(this);
m_delLabel->hide();
m_widgetlayout->addWidget(m_iconLabel);
m_widgetlayout->addWidget(m_pathLabel);
m_widgetlayout->addStretch();
m_widgetlayout->addWidget(m_delLabel);
}
/**
* @brief FolderListItem::getPath
* @return
*/
QString FolderListItem::getPath() {
return m_path;
}
/**
* @brief FolderListItem::enterEvent
* @param event
*/
void FolderListItem::enterEvent(QEvent *event) {
m_delLabel->show();
m_widget->setStyleSheet("QWidget#mWidget{background: rgba(0,0,0,0.1);}");
QWidget::enterEvent(event);
}
/**
* @brief FolderListItem::leaveEvent
* @param event
*/
void FolderListItem::leaveEvent(QEvent *event) {
m_delLabel->hide();
m_widget->setStyleSheet("QWidget#mWidget{background: transparent;}");
QWidget::leaveEvent(event);
}
/**
* @brief FolderListItem::eventFilter
* @param watched
* @param event
* @return
*/
bool FolderListItem::eventFilter(QObject *watched, QEvent *event) {
if(watched == m_delLabel) {
if(event->type() == QEvent::MouseButtonPress) {
// qDebug()<<"pressed!";
Q_EMIT this->onDelBtnClicked(m_path);
}
}
return QObject::eventFilter(watched, event);
}

View File

@ -0,0 +1,154 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef SETTINGSWIDGET_H
#define SETTINGSWIDGET_H
#include <QWidget>
#include <QDialog>
#include <QFrame>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QRadioButton>
#include <QButtonGroup>
#include <QPushButton>
#include <QScrollArea>
#include <QTimer>
#include <libsearch.h>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#include "xatom-helper.h"
#endif
namespace Zeeker {
class FolderListItem : public QWidget {
Q_OBJECT
public:
explicit FolderListItem(QWidget *parent = nullptr, const QString &path = 0);
~FolderListItem();
QString getPath();
protected:
virtual void enterEvent(QEvent *);
virtual void leaveEvent(QEvent *);
bool eventFilter(QObject *, QEvent *);
private:
void initUi();
QString m_path;
QVBoxLayout * m_layout = nullptr;
QWidget * m_widget = nullptr;
QHBoxLayout * m_widgetlayout = nullptr;
QLabel * m_iconLabel = nullptr;
QLabel * m_pathLabel = nullptr;
QLabel * m_delLabel = nullptr;
Q_SIGNALS:
void onDelBtnClicked(const QString&);
};
class SettingsWidget : public QWidget {
Q_OBJECT
public:
explicit SettingsWidget(QWidget *parent = nullptr);
~SettingsWidget();
void setIndexState(bool);
void setIndexNum(int);
void showWidget();
void resetWebEngine();
private:
void initUi();
void setupBlackList(const QStringList &);
void clearLayout(QLayout *);
void refreshIndexState();
void paintEvent(QPaintEvent *);
void resize();
void showWarningDialog(const int&);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
MotifWmHints m_hints;
#endif
//标题栏
QVBoxLayout * m_mainLyt = nullptr;
QFrame * m_contentFrame = nullptr;
QVBoxLayout * m_contentLyt = nullptr;
QFrame * m_titleFrame = nullptr;
QHBoxLayout * m_titleLyt = nullptr;
QLabel * m_titleIcon = nullptr;
QLabel * m_titleLabel = nullptr;
QPushButton * m_closeBtn = nullptr;
//设置
QLabel * m_settingLabel = nullptr;
//文件索引
QLabel * m_indexTitleLabel = nullptr;
QLabel * m_indexStateLabel = nullptr;
QLabel * m_indexNumLabel = nullptr;
//文件索引设置(黑名单)
QLabel * m_indexSettingLabel = nullptr;
QLabel * m_indexDescLabel = nullptr;
QFrame * m_indexBtnFrame = nullptr;
QHBoxLayout * m_indexBtnLyt = nullptr;
QPushButton * m_addDirBtn = nullptr;
QScrollArea * m_dirListArea = nullptr;
QWidget * m_dirListWidget = nullptr;
QVBoxLayout * m_dirListLyt = nullptr;
//搜索引擎设置
QLabel * m_searchEngineLabel = nullptr;
QLabel * m_engineDescLabel = nullptr;
QButtonGroup * m_engineBtnGroup = nullptr;
QFrame * m_radioBtnFrame = nullptr;
QHBoxLayout * m_radioBtnLyt = nullptr;
QRadioButton * m_baiduBtn = nullptr;
QLabel * m_baiduLabel = nullptr;
QRadioButton * m_sougouBtn = nullptr;
QLabel * m_sougouLabel = nullptr;
QRadioButton * m_360Btn = nullptr;
QLabel * m_360Label = nullptr;
//取消与确认按钮
QFrame * m_bottomBtnFrame = nullptr;
QHBoxLayout * m_bottomBtnLyt = nullptr;
QPushButton * m_cancelBtn = nullptr;
QPushButton * m_confirmBtn = nullptr;
QTimer * m_timer;
int m_blockdirs = 0; //黑名单文件夹数量
Q_SIGNALS:
void settingWidgetClosed();
void webEngineChanged(const QString&);
private Q_SLOTS:
// void onBtnConfirmClicked();
// void onBtnCancelClicked();
void onBtnAddClicked();
void onBtnDelClicked(const QString&);
void setWebEngine(const QString&);
};
}
#endif // SETTINGSWIDGET_H

View File

@ -0,0 +1,271 @@
#include "home-page-section.h"
#define SQUARE_WIDTH 116
#define SQUARE_HEIGHT 116
#define SQUARE_ICON_SIZE 48
#define SQUARE_NAME_SIZE 108
#define BAR_WIDTH 300
#define BAR_HEIGHT 48
#define BAR_ICON_SIZE 24
#define BAR_NAME_SIZE 250
#define TITLE_HEIGHT 24
#define MAIN_LAYOUT_SPACING 6
#define ITEM_LAYOUT_SPACING 8
#define ITEM_RADIUS 4
#define ITEM_TRANS_NORMAL 0.06
#define ITEM_TRANS_HOVER 0.15
#define ITEM_TRANS_PRESS 0.06
#define ITEM_MARGINS 0,0,0,0
#define FLOW_LAYOUT_MARGIN 0
using namespace Zeeker;
HomePageSection::HomePageSection(QString title, HomePageItemShape shape, QWidget *parent) : QWidget(parent)
{
m_title = title;
m_shape = shape;
initUi();
}
HomePageSection::~HomePageSection()
{
if (m_itemsLyt) {
delete m_itemsLyt;
m_itemsLyt = NULL;
}
}
/**
* @brief HomePageSection::setItems
* @param itemList Item列表
*/
void HomePageSection::setItems(QVector<HomePageItem> itemList)
{
clear();
if (m_shape == HomePageItemShape::Square) {
Q_FOREACH (HomePageItem item, itemList) {
m_itemsLyt->addWidget(createSquareItem(item));
}
int line_num = ceil(double(itemList.length())/5);
this->setFixedHeight(TITLE_HEIGHT + MAIN_LAYOUT_SPACING + ITEM_LAYOUT_SPACING*(line_num-1) + SQUARE_HEIGHT*line_num);
} else {
Q_FOREACH (HomePageItem item, itemList) {
m_itemsLyt->addWidget(createBarItem(item));
}
int line_num = ceil(double(itemList.length())/2);
this->setFixedHeight(TITLE_HEIGHT + MAIN_LAYOUT_SPACING + ITEM_LAYOUT_SPACING*(line_num-1) + BAR_HEIGHT*line_num);
}
m_length = itemList.length();
}
int HomePageSection::length()
{
return m_length;
}
///**
// * @brief HomePageSection::appendItem 添加一项
// * @param item 要添加的item
// */
//void HomePageSection::appendItem(HomePageItem item)
//{
// if (m_shape == HomePageItemShape::Square) {
// m_itemsLyt->addWidget(createSquareItem(item));
// } else {
// m_itemsLyt->addWidget(createBarItem(item));
// }
// m_length++;
//}
//NEW_TODO
///**
// * @brief HomePageSection::insertItem 插入一项
// * @param index 插入位置
// * @param item 要插入的item
// */
//void HomePageSection::insertItem(const int &index, const HomePageSection::HomePageItem &item)
//{
//}
///**
// * @brief HomePageSection::removeOne 删除一项
// * @param key HomePageSection的key用来寻找item
// */
//void HomePageSection::removeOne(const QString &key)
//{
// Q_FOREACH (ItemWidget * item, m_itemsLyt->findChildren<ItemWidget *>()) {
// if (item->objectName() == key) {
// delete item;
// item = NULL;
// break;
// }
// }
//}
/**
* @brief HomePageSection::clear
*/
void HomePageSection::clear()
{
if(! m_itemsLyt) return;
QLayoutItem * item;
while((item = m_itemsLyt->takeAt(0)) != 0) {
if(item->widget()) {
item->widget()->setParent(NULL); //防止删除后窗口看上去没有消失
}
delete item;
}
item = NULL;
this->setFixedHeight(0);
m_length = 0;
}
/**
* @brief HomePageSection::initUi
*/
void HomePageSection::initUi()
{
m_mainLyt = new QVBoxLayout(this);
m_mainLyt->setContentsMargins(ITEM_MARGINS);
this->setLayout(m_mainLyt);
m_titleLabel = new QLabel(this);
m_titleLabel->setFixedHeight(TITLE_HEIGHT);
m_titleLabel->setText(m_title);
m_itemWidget = new QWidget(this);
m_mainLyt->setSpacing(MAIN_LAYOUT_SPACING);
m_itemsLyt = new FlowLayout(m_itemWidget, FLOW_LAYOUT_MARGIN, ITEM_LAYOUT_SPACING, ITEM_LAYOUT_SPACING);
m_itemWidget->setLayout(m_itemsLyt);
m_mainLyt->addWidget(m_titleLabel);
m_mainLyt->addWidget(m_itemWidget);
}
///**
// * @brief HomePageSection::resize 重新计算此窗口size
// */
//void HomePageSection::resize()
//{
//}
/**
* @brief HomePageSection::createSquareItem
* @param item
* @return
*/
ItemWidget *HomePageSection::createSquareItem(const HomePageItem &item)
{
ItemWidget * square_item = new ItemWidget(m_itemWidget, HomePageItemShape::Square, item);
square_item->setObjectName(item.key);
connect(square_item, &ItemWidget::clicked, this, &HomePageSection::requestAction);
return square_item;
}
/**
* @brief HomePageSection::createBarItem
* @param item
* @return
*/
ItemWidget *HomePageSection::createBarItem(const HomePageItem &item)
{
ItemWidget * bar_item = new ItemWidget(m_itemWidget, HomePageItemShape::Bar, item);
bar_item->setObjectName(item.key);
connect(bar_item, &ItemWidget::clicked, this, &HomePageSection::requestAction);
return bar_item;
}
/**
* @brief ItemWidget::ItemWidget flowlayout中的每个小窗格
* @param parent
* @param shape
* @param item
*/
ItemWidget::ItemWidget(QWidget *parent, const HomePageItemShape &shape, const HomePageItem &item) : QWidget(parent) {
this->initUi(shape, item.name, item.icon);
m_item = item;
this->installEventFilter(this);
this->setToolTip(item.name);
m_transparency = ITEM_TRANS_NORMAL;
connect(qApp, &QApplication::paletteChanged, this, [ = ]() {
if(m_namelabel) {
QString name = this->toolTip();
if(shape == HomePageItemShape::Square) {
m_namelabel->setText(m_namelabel->fontMetrics().elidedText(name, Qt::ElideRight, SQUARE_NAME_SIZE));
} else {
m_namelabel->setText(m_namelabel->fontMetrics().elidedText(name, Qt::ElideRight, BAR_NAME_SIZE));
}
}
});
}
/**
* @brief HomePageItem::setupUi item
* @param shape
* @param name
* @param icon
*/
void ItemWidget::initUi(HomePageItemShape shape, const QString& name, const QIcon& icon) {
m_iconlabel = new QLabel(this);
m_namelabel = new QLabel(this);
m_iconlabel->setAlignment(Qt::AlignCenter);
m_namelabel->setAlignment(Qt::AlignCenter);
if (shape == HomePageItemShape::Square) {
m_vlayout = new QVBoxLayout(this);
this->setLayout(m_vlayout);
m_iconlabel->setPixmap(icon.pixmap(icon.actualSize(QSize(SQUARE_ICON_SIZE, SQUARE_ICON_SIZE))));
m_namelabel->setText(m_namelabel->fontMetrics().elidedText(name, Qt::ElideRight, SQUARE_NAME_SIZE));
m_vlayout->addWidget(m_iconlabel);
m_vlayout->addWidget(m_namelabel);
this->setFixedSize(SQUARE_WIDTH, SQUARE_HEIGHT);
} else {
m_hlayout = new QHBoxLayout(this);
this->setLayout(m_hlayout);
m_iconlabel->setPixmap(icon.pixmap(icon.actualSize(QSize(BAR_ICON_SIZE, BAR_ICON_SIZE))));
m_namelabel->setText(m_namelabel->fontMetrics().elidedText(name, Qt::ElideRight, BAR_NAME_SIZE));
m_hlayout->addWidget(m_iconlabel);
m_hlayout->addWidget(m_namelabel);
m_hlayout->addStretch();
this->setFixedSize(BAR_WIDTH, BAR_HEIGHT);
}
}
bool ItemWidget::eventFilter(QObject *watched, QEvent *event) {
if(watched == this) {
if(event->type() == QEvent::MouseButtonPress) {
m_transparency = ITEM_TRANS_PRESS;
this->update();
return true;
} else if(event->type() == QEvent::MouseButtonRelease) {
Q_EMIT this->clicked(m_item.key, m_item.action, m_item.pluginId);
m_transparency = ITEM_TRANS_NORMAL;
this->update();
return true;
} else if(event->type() == QEvent::Enter) {
m_transparency = ITEM_TRANS_HOVER;
this->update();
return true;
} else if(event->type() == QEvent::Leave) {
m_transparency = ITEM_TRANS_NORMAL;
this->update();
return true;
}
}
return QObject::eventFilter(watched, event);
}
void ItemWidget::paintEvent(QPaintEvent *event) {
Q_UNUSED(event)
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QRect rect = this->rect();
p.setRenderHint(QPainter::Antialiasing); // 反锯齿;
p.setBrush(opt.palette.color(QPalette::Text));
p.setOpacity(m_transparency);
p.setPen(Qt::NoPen);
p.drawRoundedRect(rect, ITEM_RADIUS, ITEM_RADIUS);
return QWidget::paintEvent(event);
}

View File

@ -0,0 +1,90 @@
#ifndef HOMEPAGESECTION_H
#define HOMEPAGESECTION_H
#include <QWidget>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QEvent>
#include <QDebug>
#include <QPainter>
#include <QApplication>
#include <QStyleOption>
#include <math.h>
#include "flow-layout/flow-layout.h"
namespace Zeeker {
enum class HomePageItemShape {
Square = 0,
Bar
};
struct HomePageItem
{
QIcon icon;
QString name;
QString key;
QString action;
QString pluginId;
};
class ItemWidget : public QWidget {
Q_OBJECT
public:
explicit ItemWidget(QWidget *, const HomePageItemShape &, const HomePageItem &);
~ItemWidget() = default;
protected:
bool eventFilter(QObject *, QEvent *);
void paintEvent(QPaintEvent *);
private:
void initUi(HomePageItemShape, const QString&, const QIcon&);
QHBoxLayout * m_hlayout = nullptr;
QVBoxLayout * m_vlayout = nullptr;
QLabel * m_iconlabel = nullptr;
QLabel * m_namelabel = nullptr;
double m_transparency = 0;
HomePageItem m_item;
Q_SIGNALS:
void clicked(const QString &key, const QString &action, const QString &pluginId);
};
class HomePageSection : public QWidget
{
Q_OBJECT
public:
explicit HomePageSection(QString title, HomePageItemShape shape = HomePageItemShape::Square, QWidget *parent = nullptr);
~HomePageSection();
void setItems(QVector<HomePageItem> itemList);
int length();
// void appendItem(HomePageItem item);
// void insertItem(const int &index, const HomePageItem &item);
// void removeOne(const QString &key);
void clear();
Q_SIGNALS:
//emit on HomePageItem clicked
void requestAction(const QString &key, const QString &action, const QString &pluginId);
private:
QString m_title;
QVector<HomePageItem> m_items;
void initUi();
// void resize();
QVBoxLayout * m_mainLyt = nullptr;
QLabel * m_titleLabel = nullptr;
QWidget *m_itemWidget = nullptr;
FlowLayout * m_itemsLyt = nullptr;
HomePageItemShape m_shape;
int m_length;
ItemWidget* createSquareItem(const HomePageItem &item);
ItemWidget* createBarItem(const HomePageItem &item);
};
}
#endif // HOMEPAGESECTION_H

View File

@ -0,0 +1,131 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "home-page.h"
using namespace Zeeker;
#define BACKGROUND_COLOR QColor(0, 0, 0, 0)
#define MAIN_SPACING 16
#define MAIN_MARGINS 0,0,0,0
HomePage::HomePage(QWidget *parent) : QScrollArea(parent)
{
initUi();
registerSections();
}
void HomePage::initUi()
{
QPalette pal = palette();
pal.setColor(QPalette::Base, BACKGROUND_COLOR);
pal.setColor(QPalette::Window, BACKGROUND_COLOR); //使用此palette的窗口背景将为透明
m_widget = new QWidget(this);
this->setWidget(m_widget);
m_mainLyt = new QVBoxLayout(m_widget);
m_mainLyt->setSpacing(MAIN_SPACING);
m_mainLyt->setContentsMargins(MAIN_MARGINS);
m_widget->setLayout(m_mainLyt);
m_widget->setFixedWidth(this->width());
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
this->setPalette(pal);
this->setFrameShape(QFrame::Shape::NoFrame);
}
/**
* @brief HomePage::appendSection homepgae添加一个版块
* @param section
*/
void HomePage::appendSection(HomePageSection *section)
{
section->setFixedWidth(this->width());
m_mainLyt->addWidget(section);
if (m_widget->height()) {
m_widget->setFixedHeight(m_widget->height() + section->height() + MAIN_SPACING);
} else {
m_widget->setFixedHeight(m_widget->height() + section->height());
}
}
//以下为homepage各版块的信息获取的回调
//获取快速打开应用的列表
QVector<HomePageItem> get_quickly_cb()
{
QVector<HomePageItem> quickly_list;
QStringList quicklyOpenList;
quicklyOpenList << "/usr/share/applications/ksc-defender.desktop"
<< "/usr/share/applications/ukui-notebook.desktop"
<< "/usr/share/applications/eom.desktop"
<< "/usr/share/applications/pluma.desktop"
<< "/usr/share/applications/claws-mail.desktop" ;
Q_FOREACH (QString path, quicklyOpenList) {
if (QString::compare(FileUtils::getAppName(path), "Unknown App") == 0)
continue;
HomePageItem item;
item.icon = FileUtils::getAppIcon(path);
item.name = FileUtils::getAppName(path);
item.key = path;
item.action = "open";
item.pluginId = "applications";
quickly_list.append(item);
}
return quickly_list;
}
//NEW_TODO 需要读写配置文件
//获取最近打开的列表
QVector<HomePageItem> get_recently_cb()
{
// QVector<HomePageItem> recently_list;
// return recently_list;
return get_quickly_cb();
}
//NEW_TODO 需要读写配置文件
//获取常用应用的列表
QVector<HomePageItem> get_commonly_cb()
{
// QVector<HomePageItem> commonly_list;
// return commonly_list;
return get_quickly_cb();
}
/**
* @brief HomePage::registerSections
*/
void HomePage::registerSections()
{
//快速打开
HomePageSection *quickly_section = new HomePageSection(tr("Open Quickly"), HomePageItemShape::Square, m_widget);
quickly_section->setItems(get_quickly_cb());
if (quickly_section->length())
this->appendSection(quickly_section);
//最近打开
HomePageSection *recently_section = new HomePageSection(tr("Recently Opened"), HomePageItemShape::Bar, m_widget);
recently_section->setItems(get_recently_cb());
if (recently_section->length())
this->appendSection(recently_section);
//常用应用
HomePageSection *commonly_section = new HomePageSection(tr("Commonly Used"), HomePageItemShape::Square, m_widget);
commonly_section->setItems(get_commonly_cb());
if (commonly_section->length())
this->appendSection(commonly_section);
}

View File

@ -0,0 +1,48 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef HOMEPAGE_H
#define HOMEPAGE_H
#include <QScrollArea>
#include "home-page-section.h"
#include "file-utils.h"
namespace Zeeker {
class HomePage : public QScrollArea
{
Q_OBJECT
public:
explicit HomePage(QWidget *parent = nullptr);
~HomePage() = default;
private:
void initUi();
void appendSection(HomePageSection *);
QWidget * m_widget = nullptr;
QVBoxLayout * m_mainLyt = nullptr;
void registerSections();
Q_SIGNALS:
};
}
#endif // HOMEPAGE_H

View File

@ -0,0 +1,241 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "search-page-section.h"
#include <QDebug>
using namespace Zeeker;
#define RESULT_LAYOUT_MARGINS 0,0,0,0
#define RESULT_BACKGROUND_COLOR QColor(0, 0, 0, 0)
#define DETAIL_BACKGROUND_COLOR QColor(0, 0, 0, 0)
#define DETAIL_WIDGET_TRANSPARENT 0.04
#define DETAIL_WIDGET_BORDER_RADIUS 4
#define DETAIL_WIDGET_MARGINS 8,40,40,8
#define DETAIL_FRAME_MARGINS 8,0,8,0
#define DETAIL_ICON_HEIGHT 120
#define NAME_LABEL_WIDTH 280
#define ICON_SIZE QSize(96, 96)
#define LINE_STYLE "QFrame{background: rgba(0,0,0,0.2);}"
ResultArea::ResultArea(QWidget *parent) : QScrollArea(parent)
{
qRegisterMetaType<SearchPluginIface::ResultInfo>("SearchPluginIface::ResultInfo");
initUi();
}
void ResultArea::appendWidet(ResultWidget *widget)
{
//NEW_TODO
m_mainLyt->addWidget(widget);
setupConnectionsForWidget(widget);
m_widget->setFixedHeight(m_widget->height() + widget->height());
}
/**
* @brief ResultArea::setVisibleList
* @param list
*/
void ResultArea::setVisibleList(const QStringList &list)
{
Q_FOREACH (auto widget, m_widget_list) {
if (list.contains(widget->pluginId())) {
widget->setEnabled(true);
} else {
widget->setEnabled(false);
}
}
}
void ResultArea::initUi()
{
QPalette pal = palette();
pal.setColor(QPalette::Base, RESULT_BACKGROUND_COLOR);
pal.setColor(QPalette::Window, RESULT_BACKGROUND_COLOR);
this->setFrameShape(QFrame::Shape::NoFrame);
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
this->setPalette(pal);
this->setWidgetResizable(true);
this->setFrameShape(QFrame::Shape::NoFrame);
m_widget = new QWidget(this);
this->setWidget(m_widget);
m_mainLyt = new QVBoxLayout(m_widget);
m_widget->setLayout(m_mainLyt);
m_mainLyt->setContentsMargins(RESULT_LAYOUT_MARGINS);
}
void ResultArea::setupConnectionsForWidget(ResultWidget *widget)
{
connect(this, &ResultArea::startSearch, widget, &ResultWidget::startSearch);
connect(this, &ResultArea::stopSearch, widget, &ResultWidget::stopSearch);
}
DetailArea::DetailArea(QWidget *parent) : QScrollArea(parent)
{
initUi();
connect(this, &DetailArea::setWidgetInfo, m_detailWidget, &DetailWidget::setWidgetInfo);
}
void DetailArea::initUi()
{
QPalette pal = palette();
pal.setColor(QPalette::Base, DETAIL_BACKGROUND_COLOR);
pal.setColor(QPalette::Window, DETAIL_BACKGROUND_COLOR);
this->setPalette(pal);
this->setFrameShape(QFrame::Shape::NoFrame);
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
this->setWidgetResizable(true);
m_detailWidget = new DetailWidget(this);
this->setWidget(m_detailWidget);
}
DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent)
{
initUi();
}
QString escapeHtml(const QString & str) {
QString temp = str;
temp.replace("<", "&lt;");
temp.replace(">", "&gt;");
return temp;
}
void DetailWidget::setWidgetInfo(const QString &plugin_name, const SearchPluginIface::ResultInfo &info)
{
m_iconLabel->setPixmap(info.icon.pixmap(info.icon.actualSize(ICON_SIZE)));
m_iconLabel->show();
QFontMetrics fontMetrics = m_nameLabel->fontMetrics();
QString name = fontMetrics.elidedText(info.name, Qt::ElideRight, NAME_LABEL_WIDTH - 8);
m_nameLabel->setText(QString("<h3 style=\"font-weight:normal;\">%1</h3>").arg(escapeHtml(name)));
m_nameLabel->setToolTip(info.name);
m_pluginLabel->setText(plugin_name);
m_nameFrame->show();
m_line_1->show();
if (info.description.length() > 0) {
//NEW_TODO
clearLayout(m_descFrameLyt);
Q_FOREACH (SearchPluginIface::DescriptionInfo desc, info.description) {
QLabel * descLabel = new QLabel(m_descFrame);
QString show_desc = desc.key + ": " + desc.value;
descLabel->setText(show_desc);
m_descFrameLyt->addWidget(descLabel);
}
m_line_2->show();
}
clearLayout(m_actionFrameLyt);
Q_FOREACH (auto action, info.actionMap) {
//NEW_TODO
QLabel * actionLabel = new QLabel(m_actionFrame);
actionLabel->setText(action);
m_actionFrameLyt->addWidget(actionLabel);
}
m_actionFrame->show();
}
void DetailWidget::clear()
{
m_iconLabel->hide();
m_nameFrame->hide();
m_line_1->hide();
m_descFrame->hide();
m_line_2->hide();
m_actionFrame->hide();
}
void DetailWidget::initUi()
{
m_mainLyt = new QVBoxLayout(this);
this->setLayout(m_mainLyt);
m_mainLyt->setContentsMargins(DETAIL_WIDGET_MARGINS);
m_mainLyt->setAlignment(Qt::AlignHCenter);
m_iconLabel = new QLabel(this);
m_iconLabel->setFixedHeight(DETAIL_ICON_HEIGHT);
m_iconLabel->setAlignment(Qt::AlignCenter);
m_nameFrame = new QFrame(this);
m_nameFrameLyt = new QHBoxLayout(m_nameFrame);
m_nameFrame->setLayout(m_nameFrameLyt);
m_nameFrameLyt->setContentsMargins(DETAIL_FRAME_MARGINS);
m_nameLabel = new QLabel(m_nameFrame);
m_nameLabel->setMaximumWidth(NAME_LABEL_WIDTH);
m_pluginLabel = new QLabel(m_nameFrame);
m_nameFrameLyt->addWidget(m_nameLabel);
m_nameFrameLyt->addStretch();
m_nameFrameLyt->addWidget(m_pluginLabel);
m_line_1 = new QFrame(this);
m_line_1->setFixedHeight(1);
m_line_1->setLineWidth(0);
m_line_1->setStyleSheet(LINE_STYLE);
m_line_2 = new QFrame(this);
m_line_2->setFixedHeight(1);
m_line_2->setLineWidth(0);
m_line_2->setStyleSheet(LINE_STYLE);
m_descFrame = new QFrame(this);
m_descFrameLyt = new QVBoxLayout(m_descFrame);
m_descFrame->setLayout(m_descFrameLyt);
m_descFrameLyt->setContentsMargins(DETAIL_FRAME_MARGINS);
m_actionFrame = new QFrame(this);
m_actionFrameLyt = new QVBoxLayout(m_actionFrame);
m_actionFrame->setLayout(m_actionFrameLyt);
m_actionFrameLyt->setContentsMargins(DETAIL_FRAME_MARGINS);
m_mainLyt->addWidget(m_iconLabel);
m_mainLyt->addWidget(m_nameFrame);
m_mainLyt->addWidget(m_line_1);
m_mainLyt->addWidget(m_descFrame);
m_mainLyt->addWidget(m_line_2);
m_mainLyt->addWidget(m_actionFrame);
m_mainLyt->addStretch();
}
void DetailWidget::paintEvent(QPaintEvent * event)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QRect rect = this->rect();
p.setRenderHint(QPainter::Antialiasing); // 反锯齿;
p.setBrush(opt.palette.color(QPalette::Text));
p.setOpacity(DETAIL_WIDGET_TRANSPARENT);
p.setPen(Qt::NoPen);
p.drawRoundedRect(rect, DETAIL_WIDGET_BORDER_RADIUS, DETAIL_WIDGET_BORDER_RADIUS);
return QWidget::paintEvent(event);
}
void DetailWidget::clearLayout(QLayout *layout)
{
if(! layout) return;
QLayoutItem * child;
while((child = layout->takeAt(0)) != 0) {
if(child->widget()) {
child->widget()->setParent(NULL);
}
delete child;
}
child = NULL;
}

View File

@ -0,0 +1,96 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef SEARCHPAGESECTION_H
#define SEARCHPAGESECTION_H
#include <QScrollArea>
#include <QPaintEvent>
#include <QPainter>
#include <QStyleOption>
#include "result-view.h"
#include "plugininterface/search-plugin-iface.h"
namespace Zeeker {
class ResultArea : public QScrollArea
{
Q_OBJECT
public:
ResultArea(QWidget *parent = nullptr);
~ResultArea() = default;
void appendWidet(ResultWidget *);
void setVisibleList(const QStringList &);
private:
void initUi();
void setupConnectionsForWidget(ResultWidget *);
QWidget * m_widget = nullptr;
QVBoxLayout * m_mainLyt = nullptr;
QList<ResultWidget *> m_widget_list;
Q_SIGNALS:
void startSearch(const QString &);
void stopSearch();
};
class DetailWidget : public QWidget
{
Q_OBJECT
public:
DetailWidget(QWidget *parent = nullptr);
~DetailWidget() = default;
void clear();
public Q_SLOTS:
void setWidgetInfo(const QString&, const SearchPluginIface::ResultInfo&);
private:
void initUi();
void paintEvent(QPaintEvent *);
void clearLayout(QLayout *);
QVBoxLayout * m_mainLyt = nullptr;
QLabel * m_iconLabel = nullptr;
QFrame * m_nameFrame = nullptr;
QHBoxLayout * m_nameFrameLyt = nullptr;
QLabel * m_nameLabel = nullptr;
QLabel * m_pluginLabel = nullptr;
QFrame * m_line_1 = nullptr;
QFrame * m_descFrame = nullptr;
QVBoxLayout * m_descFrameLyt = nullptr;
QFrame * m_line_2 = nullptr;
QFrame * m_actionFrame = nullptr;
QVBoxLayout * m_actionFrameLyt = nullptr;
};
class DetailArea : public QScrollArea
{
Q_OBJECT
public:
DetailArea(QWidget *parent = nullptr);
~DetailArea() = default;
private:
void initUi();
DetailWidget * m_detailWidget = nullptr;
Q_SIGNALS:
void setWidgetInfo(const QString&, const SearchPluginIface::ResultInfo&);
};
}
#endif // SEARCHPAGESECTION_H

View File

@ -0,0 +1,79 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "search-page.h"
using namespace Zeeker;
#define RESULT_WIDTH 240
#define DETAIL_WIDTH 400
SearchPage::SearchPage(QWidget *parent) : QWidget(parent)
{
initUi();
initConnections();
}
void SearchPage::setSize(const int&width, const int&height)
{
m_splitter->setFixedSize(width, height);
}
void SearchPage::setPlugins(const QStringList &plugins_id)
{
Q_FOREACH (QString plugin_id, plugins_id) {
ResultWidget * widget = new ResultWidget(plugin_id, m_resultArea);
m_resultArea->appendWidet(widget);
setupConnectionsForWidget(widget);
}
}
void SearchPage::appendPlugin(const QString &plugin_id)
{
ResultWidget * widget = new ResultWidget(plugin_id, m_resultArea);
m_resultArea->appendWidet(widget);
setupConnectionsForWidget(widget);
}
void SearchPage::initUi()
{
m_splitter = new QSplitter(this);
m_resultArea = new ResultArea(m_splitter);
m_detailArea = new DetailArea(m_splitter);
m_splitter->addWidget(m_resultArea);
m_splitter->addWidget(m_detailArea);
m_splitter->setOpaqueResize(false);
QList<int> size_list;
size_list<<RESULT_WIDTH<<DETAIL_WIDTH;
m_splitter->setSizes(size_list);
m_splitter->handle(1)->setEnabled(false); //暂时禁止拖动分隔条
}
void SearchPage::initConnections()
{
connect(this, &SearchPage::startSearch, m_resultArea, &ResultArea::startSearch);
connect(this, &SearchPage::stopSearch, m_resultArea, &ResultArea::stopSearch);
}
void SearchPage::setupConnectionsForWidget(ResultWidget *widget)
{
connect(widget, &ResultWidget::currentRowChanged, m_detailArea, &DetailArea::setWidgetInfo);
connect(widget, &ResultWidget::currentRowChanged, this, &SearchPage::currentRowChanged);
connect(this, &SearchPage::currentRowChanged, widget, &ResultWidget::clearSelectedRow);
}

View File

@ -0,0 +1,53 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef SEARCHPAGE_H
#define SEARCHPAGE_H
#include <QSplitter>
#include "search-page-section.h"
namespace Zeeker {
class SearchPage : public QWidget
{
Q_OBJECT
public:
explicit SearchPage(QWidget *parent = nullptr);
~SearchPage() = default;
void setSize(const int&, const int&);
void setPlugins(const QStringList &plugins_id);
void appendPlugin(const QString &plugin_id);
private:
void initUi();
void initConnections();
void setupConnectionsForWidget(ResultWidget *);
QSplitter * m_splitter = nullptr;
ResultArea * m_resultArea = nullptr;
DetailArea * m_detailArea = nullptr;
Q_SIGNALS:
void startSearch(const QString &);
void stopSearch();
void currentRowChanged(const QString &, const SearchPluginIface::ResultInfo&);
};
}
#endif // SEARCHPAGE_H

View File

@ -0,0 +1,13 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/home-page-section.h \
$$PWD/home-page.h \
$$PWD/search-page-section.h \
$$PWD/search-page.h \
SOURCES += \
$$PWD/home-page-section.cpp \
$$PWD/home-page.cpp \
$$PWD/search-page-section.cpp \
$$PWD/search-page.cpp \

View File

@ -0,0 +1,91 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "stacked-widget.h"
using namespace Zeeker;
Zeeker::StackedWidget::StackedWidget(QWidget *)
{
this->initWidgets();
this->initConnections();
}
Zeeker::StackedWidget::~StackedWidget()
{
if (m_homePage) {
delete m_homePage;
m_homePage = NULL;
}
if (m_searchPage) {
delete m_searchPage;
m_searchPage = NULL;
}
}
/**
* @brief StackedWidget::setPage StackedWidget所显示页面
* @param type
*/
void StackedWidget::setPage(const int & type)
{
this->setCurrentIndex(type);
}
int StackedWidget::currentPage()
{
return this->currentIndex();
}
/**
* @brief StackedWidget::setPlugins
*/
void StackedWidget::setPlugins(const QStringList &plugins)
{
m_searchPage->setPlugins(plugins);
}
/**
* @brief StackedWidget::addPlugin
*/
void StackedWidget::appendPlugin(const QString &plugin)
{
m_searchPage->appendPlugin(plugin);
}
/**
* @brief StackedWidget::initWidgets stackedwidget添加窗口
*/
void StackedWidget::initWidgets()
{
//NEW_TODO
m_homePage = new HomePage;
this->insertWidget(int(StackedPage::HomePage), m_homePage);
this->setPage(int(StackedPage::HomePage));
m_searchPage = new SearchPage;
m_searchPage->setSize(this->width(), this->height());
this->insertWidget(int(StackedPage::SearchPage), m_searchPage);
}
void StackedWidget::initConnections()
{
connect(this, &StackedWidget::startSearch, m_searchPage, &SearchPage::startSearch);
connect(this, &StackedWidget::stopSearch, m_searchPage, &SearchPage::stopSearch);
}

View File

@ -0,0 +1,62 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef STACKEDWIDGET_H
#define STACKEDWIDGET_H
#include <QObject>
#include <QStackedWidget>
#include "input-box.h"
#include "home-page.h"
#include "search-page.h"
namespace Zeeker {
enum class StackedPage {
HomePage = 0,
SearchPage
};
class StackedWidget : public QStackedWidget {
Q_OBJECT
public:
StackedWidget(QWidget *);
~StackedWidget();
void setPage(const int &);
int currentPage();
void setPlugins(const QStringList&);
void appendPlugin(const QString&);
Q_SIGNALS:
void startSearch(const QString &);
void stopSearch();
private:
void initWidgets();
void initConnections();
QString m_keyword;
HomePage * m_homePage = nullptr;
SearchPage * m_searchPage = nullptr;
// StackedPage m_current_page;
};
}
#endif // STACKEDWIDGET_H

83
frontend/frontend.pro Normal file
View File

@ -0,0 +1,83 @@
QT += core gui dbus KWindowSystem xml x11extras
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
VERSION = 0.0.1
TARGET = ukui-search
TEMPLATE = app
PKGCONFIG += gio-2.0 glib-2.0 gio-unix-2.0
CONFIG += c++11 link_pkgconfig no_keywords lrelease
LIBS += -lxapian -lgsettings-qt -lquazip5 -lX11
LIBS += -lukui-log4qt
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
include(control/control.pri)
include(model/model.pri)
include(xatom/xatom.pri)
include(singleapplication/qt-single-application.pri)
include(view/view.pri)
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h \
# Default rules for deployment.
target.path = /usr/bin
!isEmpty(target.path): INSTALLS += target
data-menu.path = /usr/share/applications
data-menu.files += ../data/ukui-search-menu.desktop
data.path = /etc/xdg/autostart
data.files += ../data/ukui-search.desktop
INSTALLS += data data-menu
RESOURCES += \
resource.qrc
TRANSLATIONS += \
../translations/ukui-search/zh_CN.ts \
../translations/ukui-search/tr.ts \
../translations/ukui-search/bo.ts
qm_files.path = /usr/share/ukui-search/translations/
qm_files.files = $$OUT_PWD/.qm/*.qm
schemes.path = /usr/share/glib-2.0/schemas/
schemes.files += ../data/org.ukui.search.data.gschema.xml ../data/org.ukui.log4qt.ukui-search.gschema.xml
INSTALLS += qm_files schemes
LIBS += -L$$OUT_PWD/../libchinese-segmentation -lchinese-segmentation \
-L$$OUT_PWD/../libsearch -lukui-search
INCLUDEPATH += $$PWD/../libchinese-segmentation
DEPENDPATH += $$PWD/../libchinese-segmentation
INCLUDEPATH += $$PWD/../libsearch
DEPENDPATH += $$PWD/../libsearch
#DISTFILES += \
# ../data/ukui-search-menu.desktop \
# $$OUT_PWD/.qm/bo.qm \
# $$OUT_PWD/.qm/tr.qm \
# $$OUT_PWD/.qm/zh_CN.qm
DISTFILES += \
../data/org.ukui.log4qt.ukui-search.gschema.xml \
../data/org.ukui.search.data.gschema.xml

295
frontend/main.cpp Normal file
View File

@ -0,0 +1,295 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
* Modified by: zhangpengfei <zhangpengfei@kylinos.cn>
* Modified by: zhangzihao <zhangzihao@kylinos.cn>
*
*/
#include "mainwindow.h"
#include <QDesktopWidget>
#include <QFile>
#include <QScreen>
#include <QTranslator>
#include <QLocale>
#include <X11/Xlib.h>
#include <syslog.h>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#include <ukui-log4qt.h>
#endif
#include <QObject>
#include <QApplication>
#include "qt-single-application.h"
#include "qt-local-peer.h"
#include "libsearch.h"
#include "global-settings.h"
using namespace Zeeker;
void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QByteArray localMsg = msg.toLocal8Bit();
QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit();
bool showDebug = true;
// QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/ukui-search.log";
// QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search/ukui-search.log";
QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search.log";
if (!QFile::exists(logFilePath)) {
showDebug = false;
}
FILE *log_file = nullptr;
if (showDebug) {
log_file = fopen(logFilePath.toLocal8Bit().constData(), "a+");
}
const char *file = context.file ? context.file : "";
const char *function = context.function ? context.function : "";
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);
}
void centerToScreen(QWidget* widget) {
if(!widget)
return;
QDesktopWidget* m = QApplication::desktop();
QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos()));
int desk_x = desk_rect.width();
int desk_y = desk_rect.height();
int x = widget->width();
int y = widget->height();
widget->move(desk_x / 2 - x / 2 + desk_rect.left(), desk_y / 2 - y / 2 + desk_rect.top());
}
/*
void searchMethod(FileUtils::SearchMethod sm){
qWarning() << "searchMethod start: " << static_cast<int>(sm);
if (FileUtils::SearchMethod::INDEXSEARCH == sm || FileUtils::SearchMethod::DIRECTSEARCH == sm) {
FileUtils::searchMethod = sm;
} else {
printf("enum class error!!!\n");
qWarning("enum class error!!!\n");
}
if (FileUtils::SearchMethod::INDEXSEARCH == sm && 0 == FileUtils::_index_status) {
qWarning() << "start first index";
FirstIndex fi("/home/zhangzihao/Desktop");
fi.start();
qWarning() << "start inotify index";
// InotifyIndex ii("/home");
// ii.start();
InotifyIndex* ii = InotifyIndex::getInstance("/home");
if (!ii->isRunning()) {
ii->start();
}
qDebug()<<"Search method has been set to INDEXSEARCH";
}
qWarning() << "searchMethod end: " << static_cast<int>(FileUtils::searchMethod);
}
*/
int main(int argc, char *argv[]) {
//v101日志模块
//#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
// //Init log module
// initUkuiLog4qt("ukui-search");
//#endif
// Determine whether the home directory has been created, and if not, keep waiting.
char *p_home = NULL;
unsigned int i = 0;
while(p_home == NULL) {
::sleep(1);
++i;
p_home = getenv("HOME");
if(i % 5 == 0) {
qWarning() << "I can't find home! I'm done here!!";
printf("I can't find home! I'm done here!!");
syslog(LOG_ERR, "I can't find home! I'm done here!!\n");
}
}
p_home = NULL;
while(!QDir(QDir::homePath()).exists()) {
qWarning() << "Home is not exits!!";
printf("Home is not exits!!");
syslog(LOG_ERR, "Home is not exits!!\n");
::sleep(1);
}
// Output log to file
qInstallMessageHandler(messageOutput);
//若使用v101日志模块可以解放如下判断条件
//#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0))
// // Output log to file
// qInstallMessageHandler(messageOutput);
//#endif
// Register meta type
qDebug() << "ukui-search main start";
qRegisterMetaType<QPair<QString, QStringList>>("QPair<QString,QStringList>");
qRegisterMetaType<Document>("Document");
// If qt version bigger than 5.12, enable high dpi scaling and use high dpi pixmaps?
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
// Make sure only one ukui-search is running.
QtSingleApplication app("ukui-search", argc, argv);
app.setQuitOnLastWindowClosed(false);
if(app.isRunning()) {
app.sendMessage(QApplication::arguments().length() > 1 ? QApplication::arguments().at(1) : app.applicationFilePath());
qDebug() << QObject::tr("ukui-search is already running!");
return EXIT_SUCCESS;
}/*else {
QCommandLineParser parser;
QCommandLineOption debugOption({"d", "debug"}, QObject::tr("Display debug information"));
QCommandLineOption showsearch({"s", "show"}, QObject::tr("show search widget"));
parser.addOptions({debugOption, showsearch});
parser.process(app);
}*/
/*
// Create a fifo at ~/.config/org.ukui/ukui-search, the fifo is used to control the order of child processes' running.
QDir fifoDir = QDir(QDir::homePath()+"/.config/org.ukui/ukui-search");
if(!fifoDir.exists())
qDebug()<<"create fifo path"<<fifoDir.mkpath(fifoDir.absolutePath());
unlink(UKUI_SEARCH_PIPE_PATH);
int retval = mkfifo(UKUI_SEARCH_PIPE_PATH, 0777);
if(retval == -1)
{
qCritical()<<"creat fifo error!!";
syslog(LOG_ERR,"creat fifo error!!\n");
assert(false);
return -1;
}
qDebug()<<"create fifo success\n";
*/
// Set max_user_watches to a number which is enough big.
UkuiSearchQDBus usQDBus;
usQDBus.setInotifyMaxUserWatches();
// load chinese character and pinyin file to a Map
FileUtils::loadHanziTable("://index/pinyinWithoutTone.txt");
/*-------------InotyifyRefact Test Start---------------*/
// QTime t1 = QTime::currentTime();
// InotifyManagerRefact* imr = new InotifyManagerRefact("/home");
// imr->start();
// QTime t2 = QTime::currentTime();
// qDebug() << t1;
// qDebug() << t2;
/*-------------InotyifyRefact Test End-----------------*/
/*-------------content index Test Start---------------*/
// QTime t3 = QTime::currentTime();
// FileTypeFilter* ftf = new FileTypeFilter("/home");
// ftf->Test();
// QTime t4 = QTime::currentTime();
// delete ftf;
// ftf = nullptr;
// qDebug() << t3;
// qDebug() << t4;
/*-------------content index Test End-----------------*/
/*-------------文本搜索 Test start-----------------*/
// FileSearcher *search = new FileSearcher();
// search->onKeywordSearchContent("重要器官移植⑤白血病");
// search->onKeywordSearchContent("g,e,x");
/*-------------文本搜索 Test End-----------------*/
// Load translations
QTranslator translator;
try {
if(! translator.load("/usr/share/ukui-search/translations/" + QLocale::system().name())) throw - 1;
app.installTranslator(&translator);
} catch(...) {
qDebug() << "Load translations file" << QLocale() << "failed!";
}
QTranslator qt_translator;
try {
if(! qt_translator.load(":/res/qt-translations/qt_zh_CN.qm")) throw - 1;
app.installTranslator(&qt_translator);
} catch(...) {
qDebug() << "Load translations file" << QLocale() << "failed!";
}
//set main window to the center of screen
MainWindow *w = new MainWindow;
qApp->setWindowIcon(QIcon::fromTheme("kylin-search"));
centerToScreen(w);
//请务必在connect之后初始化mainwindow的Gsettings为了保证gsettings第一次读取到的配置值能成功应用
w->initGsettings();
app.setActivationWindow(w);
// Processing startup parameters
if(QString::compare(QString("-s"), QString(QLatin1String(argv[1]))) == 0) {
centerToScreen(w);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
XAtomHelper::getInstance()->setWindowMotifHint(w->winId(), w->m_hints);
#endif
w->show();
}
QObject::connect(&app, &QtSingleApplication::messageReceived, w, &MainWindow::bootOptionsFilter);
// Start app search thread
AppMatch::getAppMatch()->start();
// NEW_TODO
// Set threads which in global thread pool expiry time in 5ms, some prolems here
QThreadPool::globalInstance()->setExpiryTimeout(5);
// NEW_TODO
// First insdex start, the parameter us useless, should remove the parameter
// FirstIndex fi("/home/zhangzihao/Desktop");
// fi.start();
// NEW_TODO
// Inotify index start, the parameter us useless, should remove the parameter
// InotifyIndex* ii = InotifyIndex::getInstance("/home");
// ii->start();
return app.exec();
}

577
frontend/mainwindow.cpp Normal file
View File

@ -0,0 +1,577 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
* Modified by: zhangpengfei <zhangpengfei@kylinos.cn>
*
*/
#include "mainwindow.h"
#include <QHBoxLayout>
#include <QDebug>
#include <QDesktopWidget>
#include <QtX11Extras/QX11Info>
#include <syslog.h>
#include <QPalette>
#include <QScreen>
#include <QStyleOption>
#include <QPixmap>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#include <KWindowEffects>
#include "kwindowsystem.h"
#endif
#include "qt-single-application.h"
#include "global-settings.h"
#define MAIN_MARGINS 16,8,16,16
#define TITLE_MARGINS 0,0,0,0
#define UKUI_SEARCH_SCHEMAS "org.ukui.search.settings"
#define SEARCH_METHOD_KEY "indexSearch"
#define WEB_ENGINE_KEY "webEngine"
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 590
#define TITLE_HEIGHT 40
#define WINDOW_ICON_SIZE 24
#define SETTING_BTN_SIZE 30
#define SEARCH_BAR_SIZE 44
#define ASK_INDEX_TIME 5*1000
#define RESEARCH_TIME 10*1000
using namespace Zeeker;
extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed);
/**
* @brief MainWindow
* @param parent
*
* KWindowSystem::setShowingDesktop(!KWindowSystem::showingDesktop());
*
*/
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent) {
this->setAttribute(Qt::WA_TranslucentBackground, true);
this->setAutoFillBackground(false);
this->setFocusPolicy(Qt::StrongFocus);
this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
this->setWindowTitle(tr("ukui-search"));
initUi();
initTimer();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
// setProperty("useStyleWindowManager", false); //禁止拖动
m_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
m_hints.functions = MWM_FUNC_ALL;
m_hints.decorations = MWM_DECOR_BORDER;
XAtomHelper::getInstance()->setWindowMotifHint(winId(), m_hints);
QPainterPath path;
auto rect = this->rect();
rect.adjust(1, 1, -1, -1);
path.addRect(rect);
setProperty("blurRegion", QRegion(path.toFillPolygon().toPolygon()));
KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon()));
#endif
m_sys_tray_icon = new QSystemTrayIcon(this);
m_sys_tray_icon->setIcon(QIcon::fromTheme("system-search-symbolic"));
m_sys_tray_icon->setToolTip(tr("Global Search"));
m_sys_tray_icon->show();
installEventFilter(this);
initConnections();
//NEW_TODO, register plugins
// SearchPluginManager::getInstance()->registerPlugin(\\);
// m_stackedWidget->setPlugins(SearchPluginManager::getInstance()->getPluginIds());
m_stackedWidget->setPlugins(QStringList()<<"File"<<"Folder");
}
MainWindow::~MainWindow() {
#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0))
if(m_settingsWidget) {
delete m_settingsWidget;
m_settingsWidget = NULL;
}
#endif
if(m_askDialog) {
delete m_askDialog;
m_askDialog = NULL;
}
if(m_askTimer) {
delete m_askTimer;
m_askTimer = NULL;
}
if(m_search_gsettings) {
delete m_search_gsettings;
m_search_gsettings = NULL;
}
if(m_searchWidget) {
delete m_searchWidget;
m_searchWidget = NULL;
}
if(m_searchLayout) {
delete m_searchLayout;
m_searchLayout = NULL;
}
}
/**
* @brief initUi ui控件
*/
void MainWindow::initUi() {
this->setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT);
m_frame = new QFrame(this);
this->setCentralWidget(m_frame);
QVBoxLayout * mainlayout = new QVBoxLayout(m_frame);
mainlayout->setContentsMargins(MAIN_MARGINS);
m_frame->setLayout(mainlayout);
m_titleFrame = new QFrame(m_frame);//标题栏
m_titleFrame->setFixedHeight(TITLE_HEIGHT);
m_titleLyt = new QHBoxLayout(m_titleFrame);
m_titleLyt->setContentsMargins(TITLE_MARGINS);
m_iconLabel = new QLabel(m_titleFrame);
m_iconLabel->setFixedSize(WINDOW_ICON_SIZE, WINDOW_ICON_SIZE);
m_iconLabel->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(WINDOW_ICON_SIZE, WINDOW_ICON_SIZE)));
m_titleLabel = new QLabel(m_titleFrame);
m_titleLabel->setText(tr("Search"));
m_settingsBtn = new QPushButton(m_titleFrame);
m_settingsBtn->setFixedSize(SETTING_BTN_SIZE, SETTING_BTN_SIZE);
m_settingsBtn->setIcon(QIcon::fromTheme("document-properties-symbolic"));
m_settingsBtn->setProperty("useIconHighlightEffect", 0x2);
m_settingsBtn->setProperty("isWindowButton", 0x01);
m_settingsBtn->setFlat(true);
m_titleLyt->addWidget(m_iconLabel);
m_titleLyt->addWidget(m_titleLabel);
m_titleLyt->addStretch();
m_titleLyt->addWidget(m_settingsBtn);
m_stackedWidget = new StackedWidget(m_frame);//内容栏
m_searchWidget = new SeachBarWidget(this);
m_searchLayout = new SearchBarHLayout(this);
m_searchWidget->setLayout(m_searchLayout);
m_searchWidget->setFixedHeight(SEARCH_BAR_SIZE);
mainlayout->addWidget(m_titleFrame);
mainlayout->addWidget(m_stackedWidget);
mainlayout->addWidget(m_searchWidget);
//创建索引询问弹窗
m_askDialog = new CreateIndexAskDialog(this);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
MotifWmHints ask_dialog_hints;
ask_dialog_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
ask_dialog_hints.functions = MWM_FUNC_ALL;
ask_dialog_hints.decorations = MWM_DECOR_BORDER;
XAtomHelper::getInstance()->setWindowMotifHint(m_askDialog->winId(), ask_dialog_hints);
#endif
}
void MainWindow::initConnections()
{
connect(m_sys_tray_icon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivatedSlot);
QObject::connect(this, &MainWindow::searchMethodChanged, this, [ = ](FileUtils::SearchMethod sm) {
this->m_searchMethodManager.searchMethod(sm);
});
connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &MainWindow::monitorResolutionChange);
connect(qApp, &QApplication::primaryScreenChanged, this, &MainWindow::primaryScreenChangedSlot);
connect(m_askDialog, &CreateIndexAskDialog::closed, this, [ = ]() {
m_isAskDialogVisible = false;
});
connect(m_askDialog, &CreateIndexAskDialog::btnClicked, this, [ = ](const bool &is_create_index, const bool &is_ask_again) {
setSearchMethodConfig(is_create_index, is_ask_again);
});
connect(m_settingsBtn, &QPushButton::clicked, this, &MainWindow::settingsBtnClickedSlot);
//主题改变时,更新自定义标题栏的图标
connect(qApp, &QApplication::paletteChanged, this, [ = ]() {
m_iconLabel->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(WINDOW_ICON_SIZE, WINDOW_ICON_SIZE)));
});
connect(m_searchLayout, &SearchBarHLayout::requestSearchKeyword, this, &MainWindow::searchKeywordSlot);
}
/**
* @brief bootOptionsFilter
* @param opt
*/
void MainWindow::bootOptionsFilter(QString opt) {
if(opt == "-s" || opt == "--show") {
clearSearchResult();
centerToScreen(this);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
XAtomHelper::getInstance()->setWindowMotifHint(winId(), m_hints);
#endif
this->show();
this->m_searchLayout->focusIn();
this->raise();
this->activateWindow();
}
}
/**
* @brief clearSearchResult
*/
void MainWindow::clearSearchResult() {
m_searchLayout->clearText();
m_searchLayout->focusOut();
}
/**
* @brief MainWindow::trayIconActivatedSlot
* @param reason
*/
void MainWindow::trayIconActivatedSlot(QSystemTrayIcon::ActivationReason reason)
{
if(reason == QSystemTrayIcon::Trigger) {
if(!this->isVisible()) {
clearSearchResult();
centerToScreen(this);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
XAtomHelper::getInstance()->setWindowMotifHint(winId(), m_hints);
#endif
this->show();
this->m_searchLayout->focusIn(); //打开主界面时输入框夺焦,可直接输入
this->raise();
this->activateWindow();
} else {
tryHideMainwindow();
}
}
}
/**
* @brief setSearchMethodConfig
* @param create_index
* @param no_longer_ask
*/
void MainWindow::setSearchMethodConfig(const bool &create_index, const bool &no_longer_ask)
{
if(no_longer_ask) {
GlobalSettings::getInstance()->setValue(ENABLE_CREATE_INDEX_ASK_DIALOG, "false");
} else {
GlobalSettings::getInstance()->setValue(ENABLE_CREATE_INDEX_ASK_DIALOG, "true");
}
if(create_index) {
if(m_search_gsettings && m_search_gsettings->keys().contains(SEARCH_METHOD_KEY)) {
m_search_gsettings->set(SEARCH_METHOD_KEY, true);
} else {
//调用创建索引接口
Q_EMIT this->searchMethodChanged(FileUtils::SearchMethod::INDEXSEARCH);
//创建索引十秒后重新搜索一次(如果用户十秒内没有退出搜索界面且没有重新搜索)
m_researchTimer->start();
}
}
}
/**
* @brief MainWindow::settingsBtnClickedSlot
*/
void MainWindow::settingsBtnClickedSlot()
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0))
if(m_settingsWidget) { //当此窗口已存在时,仅需置顶
if(!m_settingsWidget->isVisible()) {
centerToScreen(m_settingsWidget);
}
m_settingsWidget->showWidget();
return;
}
m_settingsWidget = new SettingsWidget();
connect(this, &MainWindow::webEngineChanged, m_settingsWidget, [ = ]() {
m_settingsWidget->resetWebEngine();
});
connect(m_settingsWidget, &SettingsWidget::webEngineChanged, this, [ = ](const QString & engine) {
if(m_search_gsettings && m_search_gsettings->keys().contains(WEB_ENGINE_KEY)) {
m_search_gsettings->set(WEB_ENGINE_KEY, engine);
} else {
GlobalSettings::getInstance()->setValue(WEB_ENGINE, engine);
}
});
centerToScreen(m_settingsWidget);
m_settingsWidget->show();
connect(m_settingsWidget, &SettingsWidget::settingWidgetClosed, this, [ = ]() {
QTimer::singleShot(100, this, [ = ] {
// clearSearchResult(); //现暂定从设置页返回主页面不清空搜索结果
this->setWindowState(this->windowState() & ~Qt::WindowMinimized);
this->raise();
this->showNormal();
this->activateWindow();
});
});
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
//打开控制面板的设置页
QProcess process;
process.startDetached("ukui-control-center --search");
#endif
}
/**
* @brief MainWindow::searchKeywordSlot
* @param keyword
*/
void MainWindow::searchKeywordSlot(const QString &keyword)
{
//NEW_TODO
if(keyword == "") {
m_stackedWidget->setPage(int(StackedPage::HomePage));
m_askTimer->stop();
Q_EMIT m_stackedWidget->stopSearch();
} else {
m_stackedWidget->setPage(int(StackedPage::SearchPage));
QTimer::singleShot(10, this, [ = ]() {
//允许弹窗且当前次搜索(为关闭主界面,算一次搜索过程)未询问且当前为暴力搜索
if(GlobalSettings::getInstance()->getValue(ENABLE_CREATE_INDEX_ASK_DIALOG).toString() != "false" && !m_currentSearchAsked && FileUtils::searchMethod == FileUtils::SearchMethod::DIRECTSEARCH)
m_askTimer->start();
Q_EMIT m_stackedWidget->startSearch(keyword);
});
}
m_researchTimer->stop(); //如果搜索内容发生改变,则停止建索引后重新搜索的倒计时
}
/**
* @brief monitorResolutionChange
* @param rect
*/
void MainWindow::monitorResolutionChange(QRect rect) {
Q_UNUSED(rect);
}
/**
* @brief primaryScreenChangedSlot
* @param screen
*/
void MainWindow::primaryScreenChangedSlot(QScreen *screen) {
Q_UNUSED(screen);
}
/**
* @brief MainWindow::moveToPanel
*/
void MainWindow::moveToPanel() {
QRect availableGeometry = qApp->primaryScreen()->availableGeometry();
QRect screenGeometry = qApp->primaryScreen()->geometry();
QDBusInterface primaryScreenInterface("org.ukui.SettingsDaemon",
"/org/ukui/SettingsDaemon/wayland",
"org.ukui.SettingsDaemon.wayland",
QDBusConnection::sessionBus());
if(QDBusReply<int>(primaryScreenInterface.call("x")).isValid()) {
QDBusReply<int> x = primaryScreenInterface.call("x");
QDBusReply<int> y = primaryScreenInterface.call("y");
QDBusReply<int> width = primaryScreenInterface.call("width");
QDBusReply<int> height = primaryScreenInterface.call("height");
screenGeometry.setX(x);
screenGeometry.setY(y);
screenGeometry.setWidth(width);
screenGeometry.setHeight(height);
availableGeometry.setX(x);
availableGeometry.setY(y);
availableGeometry.setWidth(width);
availableGeometry.setHeight(height);
}
QDesktopWidget * desktopWidget = QApplication::desktop();
QRect screenMainRect = desktopWidget->screenGeometry(0);//获取设备屏幕大小
QDBusInterface interface("com.ukui.panel.desktop",
"/",
"com.ukui.panel.desktop",
QDBusConnection::sessionBus());
int position = QDBusReply<int>(interface.call("GetPanelPosition", "position"));
int height = QDBusReply<int>(interface.call("GetPanelSize", "height"));
int d = 8; //窗口边沿到任务栏距离
if(position == 0) {
//任务栏在下侧
this->move(availableGeometry.x() + availableGeometry.width() - this->width() - d, screenGeometry.y() + screenGeometry.height() - this->height() - height - d);
} else if(position == 1) {
//任务栏在上侧
this->move(availableGeometry.x() + availableGeometry.width() - this->width() - d, screenGeometry.y() + height + d);
} else if(position == 2) {
//任务栏在左侧
this->move(screenGeometry.x() + height + d, screenGeometry.y() + screenGeometry.height() - this->height() - d);
} else if(position == 3) {
//任务栏在右侧
this->move(screenGeometry.x() + screenGeometry.width() - this->width() - height - d, screenGeometry.y() + screenGeometry.height() - this->height() - d);
}
}
/**
* @brief MainWindow::centerToScreen 使
* @param widget
*/
void MainWindow::centerToScreen(QWidget* widget) {
if(!widget)
return;
QDesktopWidget* m = QApplication::desktop();
QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos()));
int desk_x = desk_rect.width();
int desk_y = desk_rect.height();
int x = widget->width();
int y = widget->height();
QDBusInterface primaryScreenInterface("org.ukui.SettingsDaemon",
"/org/ukui/SettingsDaemon/wayland",
"org.ukui.SettingsDaemon.wayland",
QDBusConnection::sessionBus());
if(QDBusReply<int>(primaryScreenInterface.call("x")).isValid()) {
QDBusReply<int> width = primaryScreenInterface.call("width");
QDBusReply<int> height = primaryScreenInterface.call("height");
desk_x = width;
desk_y = height;
}
widget->move(desk_x / 2 - x / 2 + desk_rect.left(), desk_y / 2 - y / 2 + desk_rect.top());
}
void MainWindow::initGsettings() {
const QByteArray id(UKUI_SEARCH_SCHEMAS);
if(QGSettings::isSchemaInstalled(id)) {
m_search_gsettings = new QGSettings(id);
connect(m_search_gsettings, &QGSettings::changed, this, [ = ](const QString & key) {
if(key == SEARCH_METHOD_KEY) {
bool is_index_search = m_search_gsettings->get(SEARCH_METHOD_KEY).toBool();
this->setSearchMethod(is_index_search);
} else if(key == WEB_ENGINE_KEY) {
QString web_engine = m_search_gsettings->get(WEB_ENGINE_KEY).toString();
GlobalSettings::getInstance()->setValue(WEB_ENGINE, web_engine);
Q_EMIT this->webEngineChanged();
}
});
if(m_search_gsettings->keys().contains(SEARCH_METHOD_KEY)) {
bool is_index_search = m_search_gsettings->get(SEARCH_METHOD_KEY).toBool();
this->setSearchMethod(is_index_search);
}
if(m_search_gsettings->keys().contains(WEB_ENGINE_KEY)) {
QString web_engine = m_search_gsettings->get(WEB_ENGINE_KEY).toString();
GlobalSettings::getInstance()->setValue(WEB_ENGINE, web_engine);
}
}
}
//使用GSetting获取当前窗口应该使用的透明度
double MainWindow::getTransparentData() {
return GlobalSettings::getInstance()->getValue(TRANSPARENCY_KEY).toDouble();
}
void MainWindow::initTimer() {
m_askTimer = new QTimer;
m_askTimer->setInterval(ASK_INDEX_TIME);
connect(m_askTimer, &QTimer::timeout, this, [ = ]() {
if(this->isVisible()) {
m_isAskDialogVisible = true;
m_askDialog->show();
m_currentSearchAsked = true;
}
m_askTimer->stop();
});
m_researchTimer = new QTimer;
m_researchTimer->setInterval(RESEARCH_TIME);
connect(m_researchTimer, &QTimer::timeout, this, [ = ]() {
if(this->isVisible()) {
m_searchLayout->reSearch();
}
m_researchTimer->stop();
});
connect(m_searchLayout, &SearchBarHLayout::requestSearchKeyword, this, [ = ](QString text) {
if(text == "" || text.isEmpty()) {
m_askTimer->stop();
} else {
//允许弹窗且当前次搜索(为关闭主界面,算一次搜索过程)未询问且当前为暴力搜索
if(GlobalSettings::getInstance()->getValue(ENABLE_CREATE_INDEX_ASK_DIALOG).toString() != "false" && !m_currentSearchAsked && FileUtils::searchMethod == FileUtils::SearchMethod::DIRECTSEARCH)
m_askTimer->start();
}
});
}
/**
* @brief MainWindow::tryHideMainwindow
*/
bool MainWindow::tryHideMainwindow()
{
if (!m_isAskDialogVisible) {
qDebug()<<"Mainwindow will be hidden";
m_currentSearchAsked = false;
this->hide();
m_askTimer->stop();
m_researchTimer->stop();
Q_EMIT m_stackedWidget->stopSearch();
return true;
} else {
//有上层弹窗未关闭,不允许隐藏主界面
qWarning()<<"There is a dialog onside, so that mainwindow can not be hidden.";
return false;
}
}
/**
* @brief MainWindow::setSearchMethod
* @param is_index_search true为索引搜索false为暴力搜索
*/
void MainWindow::setSearchMethod(const bool &is_index_search) {
if(is_index_search) {
//调用创建索引接口
Q_EMIT this->searchMethodChanged(FileUtils::SearchMethod::INDEXSEARCH);
//创建索引十秒后重新搜索一次(如果用户十秒内没有退出搜索界面且没有重新搜索)
m_researchTimer->start();
} else {
Q_EMIT this->searchMethodChanged(FileUtils::SearchMethod::DIRECTSEARCH);
m_researchTimer->stop();
}
}
/**
* @brief MainWindow::keyPressEvent esc键关闭主界面
* @param event
*/
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape) {
tryHideMainwindow();
}
return QWidget::keyPressEvent(event);
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::ActivationChange) {
if(QApplication::activeWindow() != this) {
tryHideMainwindow();
}
}
return QMainWindow::eventFilter(watched,event);
}
void MainWindow::paintEvent(QPaintEvent *event) {
Q_UNUSED(event)
double trans = getTransparentData();
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QRect rect = this->rect();
p.setRenderHint(QPainter::Antialiasing); // 反锯齿;
p.setBrush(opt.palette.color(QPalette::Base));
p.setOpacity(trans);
p.setPen(Qt::NoPen);
// p.drawRoundedRect(rect, 6, 6);
p.drawRect(rect);
return QWidget::paintEvent(event);
}

153
frontend/mainwindow.h Normal file
View File

@ -0,0 +1,153 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
* Modified by: zhangpengfei <zhangpengfei@kylinos.cn>
*
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QHBoxLayout>
#include <QPropertyAnimation>
#include <QPaintEvent>
#include <QPainterPath>
#include <QPainter>
#include <QtMath>
#include <QEvent>
#include <QSpacerItem>
#include <QKeyEvent>
#include <QPropertyAnimation>
#include <QGraphicsDropShadowEffect>
#include <QSettings>
#include <QPropertyAnimation>
#include <QFileInfo>
#include <QLabel>
#include <QFrame>
#include <QPushButton>
#include <QKeyEvent>
#include <QGSettings/QGSettings>
#include <QSystemTrayIcon>
#include <QTimer>
#include "index/index-generator.h"
#include "libsearch.h"
#include "create-index-ask-dialog.h"
#include "stacked-widget.h"
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#include "xatom-helper.h"
#endif
#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0))
#include "settings-widget.h"
#endif
namespace Zeeker {
class SearchResult;
class MainWindow : public QMainWindow {
friend class SearchResult;
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
/**
* @brief Load the main window
*/
// The position which mainwindow shows follow the ukui-panel.
void moveToPanel();
// The position which mainwindow shows in the center of screen where the cursor in.
void centerToScreen(QWidget* widget);
void initGsettings();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
MotifWmHints m_hints;
#endif
private:
QFrame * m_frame = nullptr; // Main frame
QFrame * m_titleFrame = nullptr; // Title bar frame
QHBoxLayout * m_titleLyt = nullptr; // Title layout
QLabel * m_iconLabel = nullptr; // Icon lable
QLabel * m_titleLabel = nullptr; // Title lable
QPushButton * m_settingsBtn = nullptr; // Menu button
StackedWidget * m_stackedWidget = nullptr; // Stacked widget
SearchBarHLayout * m_searchLayout = nullptr; // Search bar layout
SeachBarWidget * m_searchWidget = nullptr; // Search bar
#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0))
SettingsWidget * m_settingsWidget = nullptr; // Settings Widget
#endif
QStringList m_dirList;
QQueue<QString> *m_search_result_file = nullptr;
QQueue<QString> *m_search_result_dir = nullptr;
QQueue<QPair<QString, QStringList>> *m_search_result_content = nullptr;
QSystemTrayIcon *m_sys_tray_icon = nullptr;
CreateIndexAskDialog * m_askDialog = nullptr;
bool m_isAskDialogVisible = false;
QTimer * m_askTimer = nullptr; //询问是否创建索引弹窗弹出的计时器
QTimer * m_researchTimer = nullptr; //创建索引后重新执行一次搜索的计时器
bool m_currentSearchAsked = false; //本次搜索是否已经询问过是否创建索引了
QGSettings * m_search_gsettings = nullptr;
SearchMethodManager m_searchMethodManager;
void setSearchMethod(const bool&);
double getTransparentData();
void initTimer();
bool tryHideMainwindow();
void setSearchMethodConfig(const bool&, const bool&);
protected:
void paintEvent(QPaintEvent *);
void keyPressEvent(QKeyEvent *event);
bool eventFilter(QObject *watched, QEvent *event) override;
void initUi();
void initConnections();
Q_SIGNALS:
void searchMethodChanged(FileUtils::SearchMethod);
void webEngineChanged();
public Q_SLOTS:
/**
* @brief Monitor screen resolution
* @param rect: Screen resolution
*/
void monitorResolutionChange(QRect rect);
/**
* @brief Monitor primary screen changes
* @param screen: Primary screen
*/
void primaryScreenChangedSlot(QScreen *screen);
void bootOptionsFilter(QString opt); // 过滤终端命令
void clearSearchResult(); //清空搜索结果
void trayIconActivatedSlot(QSystemTrayIcon::ActivationReason reason);
void settingsBtnClickedSlot();
void searchKeywordSlot(const QString&);
};
}
#endif // MAINWINDOW_H

0
frontend/model/README.md Normal file
View File

9
frontend/model/model.pri Normal file
View File

@ -0,0 +1,9 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/search-result-manager.h \
$$PWD/search-result-model.h \
SOURCES += \
$$PWD/search-result-manager.cpp \
$$PWD/search-result-model.cpp \

View File

@ -0,0 +1,126 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "search-result-manager.h"
using namespace Zeeker;
SearchResultManager::SearchResultManager(const QString& plugin_id, QObject *parent) : QObject(parent)
{
m_plugin_id = plugin_id;
m_result_queue = new QQueue<SearchPluginIface::ResultInfo>;
m_get_result_thread = new ReceiveResultThread(m_result_queue);
initConnections();
}
void SearchResultManager::startSearch(const QString &keyword)
{
//NEW_TODO 加锁?停止线程?重新搜索?
stopSearch();
m_result_queue->clear();
SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_plugin_id);
// plugin->KeywordSearch(keyword, m_result_queue);
/*********************测试用数据*********************/
SearchPluginIface::ResultInfo test_info;
if (m_plugin_id == "File") {
test_info.icon = QIcon::fromTheme("ukui-control-center");
test_info.name = "搜索";
QVector<SearchPluginIface::DescriptionInfo> desc;
SearchPluginIface::DescriptionInfo desc_1;
desc_1.key = "描述";
desc_1.value = "控制面板搜索插件";
desc.append(desc_1);
QMap<QString,QString> actions;
actions.insert("ukcc-search","打开");
test_info.description = desc;
test_info.actionMap = actions;
m_result_queue->append(test_info);
} else {
test_info.icon = QIcon::fromTheme("ukui-control-center");
test_info.name = "文件";
QVector<SearchPluginIface::DescriptionInfo> desc;
SearchPluginIface::DescriptionInfo desc_1;
SearchPluginIface::DescriptionInfo desc_2;
desc_1.key = "描述";
desc_1.value = "一个文件";
desc_2.key = "路径";
desc_2.value = "一个路径";
desc.append(desc_1);
desc.append(desc_2);
QMap<QString,QString> actions;
actions.insert("file1","打开");
actions.insert("file2","复制路径");
test_info.description = desc;
test_info.actionMap = actions;
m_result_queue->append(test_info);
}
/********************测试用数据********************/
qWarning()<<m_plugin_id<<"------------------>start by others";
m_get_result_thread->start();
}
/**
* @brief SearchResultManager::stopSearch 退
*/
void SearchResultManager::stopSearch()
{
if(m_get_result_thread->isRunning()) {
qWarning()<<m_plugin_id<<"-------------->stopped by others";
m_get_result_thread->requestInterruption();
m_get_result_thread->quit();
}
}
void SearchResultManager::initConnections()
{
connect(m_get_result_thread, &ReceiveResultThread::gotResultInfo, this, &SearchResultManager::gotResultInfo);
}
ReceiveResultThread::ReceiveResultThread(QQueue<SearchPluginIface::ResultInfo> * result_queue, QObject *parent)
{
m_result_queue = result_queue;
}
//NEW_TODO 还未对队列加锁
void ReceiveResultThread::run()
{
QTimer * m_timer = new QTimer;
m_timer->setInterval(3000);
bool is_empty;
while(!isInterruptionRequested()) {
is_empty = false;
if(!m_result_queue->isEmpty()) {
Q_EMIT this->gotResultInfo(m_result_queue->dequeue());
} else {
is_empty = true;
}
if(m_timer->isActive() && m_timer->remainingTime() < 0.01) {
this->requestInterruption();
qWarning()<<"-------------->stopped by self";
}
if(is_empty && !m_timer->isActive()) {
m_timer->start();
} else if(!is_empty) {
m_timer->stop();
} else {
msleep(100);
}
}
}

View File

@ -0,0 +1,71 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef SEARCHRESULTMANAGER_H
#define SEARCHRESULTMANAGER_H
#include <QQueue>
#include <QThread>
#include <QTimer>
#include <QDebug>
#include "pluginmanage/search-plugin-manager.h"
namespace Zeeker {
class ReceiveResultThread : public QThread {
Q_OBJECT
public:
ReceiveResultThread(QQueue<SearchPluginIface::ResultInfo> * result_queue, QObject * parent = nullptr);
~ReceiveResultThread() = default;
protected:
void run() override;
private:
QQueue<SearchPluginIface::ResultInfo> * m_result_queue;
Q_SIGNALS:
void gotResultInfo(const SearchPluginIface::ResultInfo&);
};
class SearchResultManager : public QObject
{
Q_OBJECT
public:
explicit SearchResultManager(const QString &plugin_id, QObject *parent = nullptr);
~SearchResultManager() = default;
public Q_SLOTS:
void startSearch(const QString &);
void stopSearch();
private:
void initConnections();
QString m_plugin_id;
QQueue<SearchPluginIface::ResultInfo> * m_result_queue;
ReceiveResultThread * m_get_result_thread = nullptr;
Q_SIGNALS:
void gotResultInfo(const SearchPluginIface::ResultInfo&);
};
}
#endif // SEARCHRESULTMANAGER_H

View File

@ -0,0 +1,102 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include "search-result-model.h"
using namespace Zeeker;
SearchResultModel::SearchResultModel(const QString &plugin_id)
{
m_item = new SearchResultItem;
m_plugin_id = plugin_id;
m_search_manager = new SearchResultManager(plugin_id);
initConnections();
}
QModelIndex SearchResultModel::index(int row, int column, const QModelIndex &parent) const
{
if(row < 0 || row > m_item->m_result_info_list.length() - 1)
return QModelIndex();
// QVector<SearchPluginIface::ResultInfo> * m_info = &m_result_info_list;
return createIndex(row, column, m_item);
}
QModelIndex SearchResultModel::parent(const QModelIndex &child) const
{
return QModelIndex();
}
int SearchResultModel::rowCount(const QModelIndex &index) const
{
return index.isValid() ? 0 : m_item->m_result_info_list.length();
}
int SearchResultModel::columnCount(const QModelIndex &index) const
{
return index.isValid() ? 0 : 1;
}
QVariant SearchResultModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
return QVariant();
switch(role) {
case Qt::DecorationRole: {
return m_item->m_result_info_list.at(index.row()).icon;
}
case Qt::DisplayRole: {
return m_item->m_result_info_list.at(index.row()).name;
}
default:
return QVariant();
}
return QVariant();
}
//bool SearchResultModel::insertRows(int row, int count, const QModelIndex &parent)
//{
// this->beginInsertRows(parent, row, count);
// this->endInsertRows();
// return true;
//}
void SearchResultModel::appendInfo(const SearchPluginIface::ResultInfo &info)
{
this->beginResetModel();
qWarning()<<"Got a result. name ="<<info.name;
m_item->m_result_info_list.append(info);
this->endResetModel();
}
void SearchResultModel::initConnections()
{
connect(this, &SearchResultModel::startSearch, m_search_manager, &SearchResultManager::startSearch);
connect(this, &SearchResultModel::stopSearch, m_search_manager, &SearchResultManager::stopSearch);
connect(m_search_manager, &SearchResultManager::gotResultInfo, this, &SearchResultModel::appendInfo);
}
const SearchPluginIface::ResultInfo &SearchResultModel::getInfo(const QModelIndex &index)
{
return m_item->m_result_info_list.at(index.row());
}
SearchResultItem::SearchResultItem(QObject *parent) : QObject(parent)
{
}

View File

@ -0,0 +1,67 @@
/*
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef SEARCHRESULTMODEL_H
#define SEARCHRESULTMODEL_H
#include <QAbstractItemModel>
#include "search-result-manager.h"
namespace Zeeker {
class SearchResultItem : public QObject {
friend class SearchResultModel;
Q_OBJECT
public:
explicit SearchResultItem(QObject *parent = nullptr);
~SearchResultItem() = default;
private:
//此插件所有搜索结果<具体信息>
QVector<SearchPluginIface::ResultInfo> m_result_info_list;
};
class SearchResultModel : public QAbstractItemModel
{
Q_OBJECT
public:
SearchResultModel(const QString &plugin_id);
~SearchResultModel() = default;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
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;
// bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())override;
const SearchPluginIface::ResultInfo & getInfo(const QModelIndex&);
public Q_SLOTS:
void appendInfo(const SearchPluginIface::ResultInfo &);
Q_SIGNALS:
void startSearch(const QString &);
void stopSearch();
private:
void initConnections();
SearchResultItem * m_item = nullptr;
QString m_plugin_id;
SearchResultManager * m_search_manager = nullptr;
};
}
#endif // SEARCHRESULTMODEL_H

View File

@ -0,0 +1 @@
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{opacity:0.85;}</style></defs><title>close</title><path class="cls-1" d="M8.71,8l5.14-5.15a.49.49,0,0,0-.7-.7L8,7.29,2.85,2.15a.49.49,0,0,0-.7.7L7.29,8,2.15,13.15a.48.48,0,0,0,0,.7.48.48,0,0,0,.7,0L8,8.71l5.15,5.14a.48.48,0,0,0,.7,0,.48.48,0,0,0,0-.7Z"/></svg>

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>edit-find-symbolic</title>
<g id="Icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Icon-Sets" transform="translate(-68.000000, -2529.000000)" fill-rule="nonzero">
<g id="编组-9" transform="translate(0.000000, 2399.000000)">
<g id="编组" transform="translate(68.000000, 130.000000)">
<polygon id="矩形备份" fill="#000000" opacity="0" points="0 0 16 0 16 16 0 16"/>
<path d="M6.86630772,1 C8.48762671,1 9.95614366,1.64816049 11.0189488,2.69780957 C12.0771269,3.74288891 12.7327736,5.18634211 12.7327736,6.78146875 C12.7327736,8.28192337 12.1523076,9.64806734 11.2023613,10.6749557 L11.2023613,10.6749557 L14.9869478,14.4127374 L10.6532367,11.3057557 C9.58274699,12.0665702 8.28388099,12.5629531 6.86630772,12.5629531 C5.2449219,12.5629531 3.77647181,11.9148388 2.71373977,10.8652353 C1.65557494,9.82014255 1,8.37664384 1,6.78146875 C1,5.18630217 1.65557811,3.74280894 2.71374274,2.69771882 C3.77647668,1.64811584 5.24492743,1 6.86630772,1 Z" id="路径" stroke="#2FB3E8" stroke-width="2"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="98px" height="87px" viewBox="0 0 98 87" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59 (86127) - https://sketch.com -->
<title>image-viewer-app-symbolic</title>
<desc>Created with Sketch.</desc>
<defs>
<filter x="-2.4%" y="-2.7%" width="104.7%" height="105.3%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="4" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="综合搜索" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.200000003">
<g id="搜索结果——网页" transform="translate(-883.000000, -627.000000)">
<g id="编组-2" filter="url(#filter-1)" transform="translate(447.000000, 427.000000)">
<g id="image-viewer-app-symbolic" transform="translate(436.000000, 200.000000)">
<g id="图层_2" transform="translate(4.000000, 5.000000)">
<path d="M24,72 L12,72 C5.4,72 0,66.6 0,60 L0,12 C0,5.4 5.4,0 12,0 L78,0 C84.6,0 90,5.4 90,12 L90,60" id="路径" stroke="#1F2022" stroke-width="6" stroke-linecap="round"></path>
<path d="M51,15 C34.2,15 21,28.2 21,45 C21,61.8 34.2,75 51,75 C67.8,75 81,61.8 81,45 C81,28.2 67.8,15 51,15 Z M51,21 C64.2,21 75,31.8 75,45 C75,58.2 64.2,69 51,69 C37.8,69 27,58.2 27,45 C27,31.8 37.8,21 51,21 Z" id="circle2567-9" fill="#1F2022" fill-rule="nonzero"></path>
<path d="M71.4,60.6 L67.2,64.8 L80.1,77.7 C81.259798,78.859798 83.140202,78.859798 84.3,77.7 C85.459798,76.540202 85.459798,74.659798 84.3,73.5 L71.4,60.6 L71.4,60.6 Z" id="path2570-36" fill="#1F2022"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

9
frontend/resource.qrc Normal file
View File

@ -0,0 +1,9 @@
<RCC>
<qresource prefix="/">
<file>res/icons/edit-find-symbolic.svg</file>
<file>res/icons/desktop.png</file>
<file>res/icons/close.svg</file>
<file>res/qt-translations/qt_zh_CN.qm</file>
<file>res/icons/net-disconnected.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,205 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
**
****************************************************************************/
#include "qt-local-peer.h"
#include <QCoreApplication>
#include <QDataStream>
#include <QTime>
#if defined(Q_OS_UNIX)
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif
namespace QtLP_Private {
#include "qt-locked-file.cpp"
#include "qt-locked-file-unix.cpp"
}
const char* QtLocalPeer::ack = "ack";
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
: QObject(parent), id(appId) {
QString prefix = id;
if(id.isEmpty()) {
id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN)
id = id.toLower();
#endif
prefix = id.section(QLatin1Char('/'), -1); //完整路径按‘/’分隔后取最后一个字段
}
prefix.remove(QRegExp("[^a-zA-Z]")); //去掉名称中的非字母
prefix.truncate(6); //取前六位
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
socketName = QLatin1String("qtsingleapp-") + prefix
+ QLatin1Char('-') + QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if(!pProcessIdToSessionId) {
QLibrary lib("kernel32");
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if(pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile"); //tmp目录下的锁文件
lockFile.setFileName(lockName);
lockFile.open(QIODevice::ReadWrite);
}
bool QtLocalPeer::isClient() {
if(lockFile.isLocked())
return false;
if(!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
return true;
//由于文件锁的存在仅当本进程第一次启动时能执行到此并使server进行监听和关联槽函数
bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
// ### Workaround
if(!res && server->serverError() == QAbstractSocket::AddressInUseError) {
QFile::remove(QDir::cleanPath(QDir::tempPath()) + QLatin1Char('/') + socketName);
res = server->listen(socketName);
}
#endif
if(!res)
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection);
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout) {
if(!isClient())
return false;
QLocalSocket socket;
bool connOk = false;
for(int i = 0; i < 2; i++) {
// Try twice, in case the other instance is just starting up
socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout / 2);
if(connOk || i)
break;
int ms = 250;
#if defined(Q_OS_WIN)
Sleep(DWORD(ms));
#else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, NULL);
#endif
}
if(!connOk)
return false;
QByteArray uMsg(message.toUtf8());
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout);
if(res) {
res &= socket.waitForReadyRead(timeout); // wait for ack
if(res)
res &= (socket.read(qstrlen(ack)) == ack);
}
return res;
}
/**
* @brief QtLocalPeer::receiveConnection server,server接收到newConnection信号并触发此槽函数
*/
void QtLocalPeer::receiveConnection() {
QLocalSocket* socket = server->nextPendingConnection(); //获取新进程的socket
if(!socket)
return;
while(true) {
if(socket->state() == QLocalSocket::UnconnectedState) {
qWarning("QtLocalPeer: Peer disconnected");
delete socket;
return;
}
if(socket->bytesAvailable() >= qint64(sizeof(quint32)))
break;
socket->waitForReadyRead();
}
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
ds >> remaining;
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();
do {
got = ds.readRawData(uMsgBuf, remaining);
remaining -= got;
uMsgBuf += got;
} while(remaining && got >= 0 && socket->waitForReadyRead(2000));
if(got < 0) {
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket;
return;
}
QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
Q_EMIT messageReceived(message); //获取新进程的启动信息并作为信号发送给前端
}

View File

@ -0,0 +1,80 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
**
****************************************************************************/
#ifndef QTLOCALPEER_H
#define QTLOCALPEER_H
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include "qt-locked-file.h"
class QtLocalPeer : public QObject {
Q_OBJECT
public:
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
bool isClient();
bool sendMessage(const QString &message, int timeout);
QString applicationId() const {
return id;
}
Q_SIGNALS:
void messageReceived(const QString &message);
protected Q_SLOTS:
void receiveConnection();
protected:
QString id;
QString socketName;
QLocalServer* server;
QtLP_Private::QtLockedFile lockFile;
private:
static const char* ack;
};
#endif // QTLOCALPEER_H

View File

@ -0,0 +1,113 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "qt-locked-file.h"
bool QtLockedFile::lock(LockMode mode, bool block) {
if(!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if(mode == NoLock)
return unlock();
if(mode == m_lock_mode)
return true;
if(m_lock_mode != NoLock)
unlock();
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
int cmd = block ? F_SETLKW : F_SETLK;
int ret = fcntl(handle(), cmd, &fl);
if(ret == -1) {
if(errno != EINTR && errno != EAGAIN)
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock() {
if(!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if(!isLocked())
return true;
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
int ret = fcntl(handle(), F_SETLKW, &fl);
if(ret == -1) {
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = NoLock;
return true;
}
QtLockedFile::~QtLockedFile() {
if(isOpen())
unlock();
}

View File

@ -0,0 +1,189 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qt-locked-file.h"
/*!
\class QtLockedFile
\brief The QtLockedFile class extends QFile with advisory locking
functions.
A file may be locked in read or write mode. Multiple instances of
\e QtLockedFile, created in multiple processes running on the same
machine, may have a file locked in read mode. Exactly one instance
may have it locked in write mode. A read and a write lock cannot
exist simultaneously on the same file.
The file locks are advisory. This means that nothing prevents
another process from manipulating a locked file using QFile or
file system functions offered by the OS. Serialization is only
guaranteed if all processes that access the file use
QLockedFile. Also, while holding a lock on a file, a process
must not open the same file again (through any API), or locks
can be unexpectedly lost.
The lock provided by an instance of \e QtLockedFile is released
whenever the program terminates. This is true even when the
program crashes and no destructors are called.
*/
/*! \enum QtLockedFile::LockMode
This enum describes the available lock modes.
\value ReadLock A read lock.
\value WriteLock A write lock.
\value NoLock Neither a read lock nor a write lock.
*/
/*!
Constructs an unlocked \e QtLockedFile object. This constructor
behaves in the same way as \e QFile::QFile().
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile()
: QFile() {
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Constructs an unlocked QtLockedFile object with file \a name. This
constructor behaves in the same way as \e QFile::QFile(const
QString&).
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile(const QString &name)
: QFile(name) {
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Opens the file in OpenMode \a mode.
This is identical to QFile::open(), with the one exception that the
Truncate mode flag is disallowed. Truncation would conflict with the
advisory file locking, since the file would be modified before the
write lock is obtained. If truncation is required, use resize(0)
after obtaining the write lock.
Returns true if successful; otherwise false.
\sa QFile::open(), QFile::resize()
*/
bool QtLockedFile::open(OpenMode mode) {
if(mode & QIODevice::Truncate) {
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
return false;
}
return QFile::open(mode);
}
/*!
Returns \e true if this object has a in read or write lock;
otherwise returns \e false.
\sa lockMode()
*/
bool QtLockedFile::isLocked() const {
return m_lock_mode != NoLock;
}
/*!
Returns the type of lock currently held by this object, or \e
QtLockedFile::NoLock.
\sa isLocked()
*/
QtLockedFile::LockMode QtLockedFile::lockMode() const {
return m_lock_mode;
}
/*!
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
Obtains a lock of type \a mode. The file must be opened before it
can be locked.
If \a block is true, this function will block until the lock is
aquired. If \a block is false, this function returns \e false
immediately if the lock cannot be aquired.
If this object already has a lock of type \a mode, this function
returns \e true immediately. If this object has a lock of a
different type than \a mode, the lock is first released and then a
new lock is obtained.
This function returns \e true if, after it executes, the file is
locked by this object, and \e false otherwise.
\sa unlock(), isLocked(), lockMode()
*/
/*!
\fn bool QtLockedFile::unlock()
Releases a lock.
If the object has no lock, this function returns immediately.
This function returns \e true if, after it executes, the file is
not locked by this object, and \e false otherwise.
\sa lock(), isLocked(), lockMode()
*/
/*!
\fn QtLockedFile::~QtLockedFile()
Destroys the \e QtLockedFile object. If any locks were held, they
are released.
*/

View File

@ -0,0 +1,97 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCKEDFILE_H
#define QTLOCKEDFILE_H
#include <QFile>
#ifdef Q_OS_WIN
#include <QVector>
#endif
#if defined(Q_OS_WIN)
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
# define QT_QTLOCKEDFILE_EXPORT
# elif defined(QT_QTLOCKEDFILE_IMPORT)
# if defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# endif
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
# elif defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTLOCKEDFILE_EXPORT
#endif
namespace QtLP_Private {
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile {
public:
enum LockMode { NoLock = 0, ReadLock, WriteLock };
QtLockedFile();
QtLockedFile(const QString &name);
~QtLockedFile();
bool open(OpenMode mode);
bool lock(LockMode mode, bool block = true);
bool unlock();
bool isLocked() const;
LockMode lockMode() const;
private:
#ifdef Q_OS_WIN
Qt::HANDLE wmutex;
Qt::HANDLE rmutex;
QVector<Qt::HANDLE> rmutexes;
QString mutexname;
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
#endif
LockMode m_lock_mode;
};
}
#endif

View File

@ -0,0 +1,357 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
**
****************************************************************************/
#include "qt-single-application.h"
#include "qt-local-peer.h"
#include <QWidget>
#include <QDesktopWidget>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusReply>
#include "mainwindow.h"
/*!
\class QtSingleApplication qtsingleapplication.h
\brief The QtSingleApplication class provides an API to detect and
communicate with running instances of an application.
This class allows you to create applications where only one
instance should be running at a time. I.e., if the user tries to
launch another instance, the already running instance will be
activated instead. Another usecase is a client-server system,
where the first started instance will assume the role of server,
and the later instances will act as clients of that server.
By default, the full path of the executable file is used to
determine whether two processes are instances of the same
application. You can also provide an explicit identifier string
that will be compared instead.
The application should create the QtSingleApplication object early
in the startup phase, and call isRunning() to find out if another
instance of this application is already running. If isRunning()
returns false, it means that no other instance is running, and
this instance has assumed the role as the running instance. In
this case, the application should continue with the initialization
of the application user interface before entering the event loop
with exec(), as normal.
The messageReceived() signal will be emitted when the running
application receives messages from another instance of the same
application. When a message is received it might be helpful to the
user to raise the application so that it becomes visible. To
facilitate this, QtSingleApplication provides the
setActivationWindow() function and the activateWindow() slot.
If isRunning() returns true, another instance is already
running. It may be alerted to the fact that another instance has
started by using the sendMessage() function. Also data such as
startup parameters (e.g. the name of the file the user wanted this
new instance to open) can be passed to the running instance with
this function. Then, the application should terminate (or enter
client mode).
If isRunning() returns true, but sendMessage() fails, that is an
indication that the running instance is frozen.
Here's an example that shows how to convert an existing
application to use QtSingleApplication. It is very simple and does
not make use of all QtSingleApplication's functionality (see the
examples for that).
\code
// Original
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyMainWidget mmw;
mmw.show();
return app.exec();
}
// Single instance
int main(int argc, char **argv)
{
QtSingleApplication app(argc, argv);
if (app.isRunning())
return !app.sendMessage(someDataString);
MyMainWidget mmw;
app.setActivationWindow(&mmw);
mmw.show();
return app.exec();
}
\endcode
Once this QtSingleApplication instance is destroyed (normally when
the process exits or crashes), when the user next attempts to run the
application this instance will not, of course, be encountered. The
next instance to call isRunning() or sendMessage() will assume the
role as the new running instance.
For console (non-GUI) applications, QtSingleCoreApplication may be
used instead of this class, to avoid the dependency on the QtGui
library.
\sa QtSingleCoreApplication
*/
void QtSingleApplication::sysInit(const QString &appId) {
actWin = 0;
peer = new QtLocalPeer(this, appId);
// connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived);
}
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a GUIenabled are passed on to the QAppliation constructor.
If you are creating a console application (i.e. setting \a
GUIenabled to false), you may consider using
QtSingleCoreApplication instead.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
: QApplication(argc, argv, GUIenabled) {
sysInit();
}
/*!
Creates a QtSingleApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
: QApplication(argc, argv) {
sysInit(appId);
}
#if QT_VERSION < 0x050000
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a type are passed on to the QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
: QApplication(argc, argv, type) {
sysInit();
}
# if defined(Q_WS_X11)
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
and \a cmap are passed on to the QApplication constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, visual, cmap) {
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap) {
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be \a appId. \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap) {
sysInit(appId);
}
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleApplication::isRunning() {
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleApplication::sendMessage(const QString &message, int timeout) {
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleApplication::id() const {
return peer->applicationId();
}
/*!
Sets the activation window of this application to \a aw. The
activation window is the widget that will be activated by
activateWindow(). This is typically the application's main window.
If \a activateOnMessage is true (the default), the window will be
activated automatically every time a message is received, just prior
to the messageReceived() signal being emitted.
\sa activateWindow(), messageReceived()
*/
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) {
actWin = aw;
//目前不需要用到此处的置顶方法,故此信号槽暂时注释掉,若后续需要根据新起进程传递的信号执行部分操作时可以把这里放开
// if (activateOnMessage)
// connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
// else
// disconnect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
}
/*!
Returns the applications activation window if one has been set by
calling setActivationWindow(), otherwise returns 0.
\sa setActivationWindow()
*/
QWidget* QtSingleApplication::activationWindow() const {
return actWin;
}
/*!
De-minimizes, raises, and activates this application's activation window.
This function does nothing if no activation window has been set.
This is a convenience function to show the user that this
application instance has been activated when he has tried to start
another instance.
This function should typically be called in response to the
messageReceived() signal. By default, that will happen
automatically, if an activation window has been set.
\sa setActivationWindow(), messageReceived(), initialize()
*/
void QtSingleApplication::activateWindow() {
//单例置顶策略由于bootOptionsFilter in mainwindow自带置顶策略故注掉此处
// if (actWin) {
// if(this->applicationState() & Qt::ApplicationInactive)
// {
// MainWindow* w=qobject_cast<MainWindow*>(actWin);
//// w->loadMainWindow();
// w->clearSearchResult();
// actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
// actWin->raise();
// actWin->showNormal();
// actWin->activateWindow();
// }
// else {
// actWin->setWindowState(actWin->windowState() & Qt::WindowMinimized);
// actWin->hide();
// }
// }
}
/*!
\fn void QtSingleApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage(), setActivationWindow(), activateWindow()
*/
/*!
\fn void QtSingleApplication::initialize(bool dummy = true)
\obsolete
*/

View File

@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
**
****************************************************************************/
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include <QApplication>
class QtLocalPeer;
#if defined(Q_OS_WIN)
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
# define QT_QTSINGLEAPPLICATION_EXPORT
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
# if defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# endif
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport)
# elif defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTSINGLEAPPLICATION_EXPORT
#endif
class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication {
Q_OBJECT
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
#if QT_VERSION < 0x050000
QtSingleApplication(int &argc, char **argv, Type type);
# if defined(Q_WS_X11)
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
bool isRunning();
QString id() const;
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const;
// Obsolete:
void initialize(bool dummy = true) {
isRunning();
Q_UNUSED(dummy)
}
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
void activateWindow();
Q_SIGNALS:
void messageReceived(const QString &message);
private:
void sysInit(const QString &appId = QString());
QtLocalPeer *peer;
QWidget *actWin;
};
#endif // QTSINGLEAPPLICATION_H

View File

@ -0,0 +1,27 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
QT *= network
greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets
qtsingleapplication-uselib:!qtsingleapplication-buildlib {
LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME
} else {
SOURCES +=
HEADERS +=
}
win32 {
contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT
else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT
}
HEADERS += \
$$PWD/qt-local-peer.h \
$$PWD/qt-locked-file.h \
$$PWD/qt-single-application.h
SOURCES += \
$$PWD/qt-local-peer.cpp \
$$PWD/qt-locked-file-unix.cpp \
$$PWD/qt-single-application.cpp \
$$PWD/qt-locked-file.cpp

View File

@ -0,0 +1,104 @@
#include "result-view.h"
#define MAIN_MARGINS 0,0,0,0
#define MAIN_SPACING 0
#define TITLE_HEIGHT 30
#define UNFOLD_LABEL_HEIGHT 24
using namespace Zeeker;
ResultWidget::ResultWidget(const QString &plugin_id, QWidget *parent) : QWidget(parent)
{
m_plugin_id = plugin_id;
this->initUi();
initConnections();
}
QString ResultWidget::pluginId()
{
return m_plugin_id;
}
void ResultWidget::setEnabled(const bool &enabled)
{
m_enabled = enabled;
}
void ResultWidget::initUi()
{
m_mainLyt = new QVBoxLayout(this);
this->setLayout(m_mainLyt);
m_mainLyt->setContentsMargins(MAIN_MARGINS);
m_mainLyt->setSpacing(MAIN_SPACING);
m_titleLabel = new TitleLabel(this);
m_titleLabel->setText(m_plugin_id);
m_titleLabel->setFixedHeight(TITLE_HEIGHT);
m_resultView = new ResultView(m_plugin_id, this);
//NEW_TODO
m_showMoreLabel = new ShowMoreLabel(this);
m_showMoreLabel->setFixedHeight(UNFOLD_LABEL_HEIGHT);
m_mainLyt->addWidget(m_titleLabel);
m_mainLyt->addWidget(m_resultView);
m_mainLyt->addWidget(m_showMoreLabel);
this->setFixedHeight(m_resultView->height() + TITLE_HEIGHT + UNFOLD_LABEL_HEIGHT);
}
void ResultWidget::initConnections()
{
connect(this, &ResultWidget::startSearch, m_resultView, &ResultView::startSearch);
connect(this, &ResultWidget::stopSearch, m_resultView, &ResultView::stopSearch);
connect(m_resultView, &ResultView::currentRowChanged, this, &ResultWidget::currentRowChanged);
connect(this, &ResultWidget::clearSelectedRow, m_resultView, &ResultView::clearSelectedRow);
}
ResultView::ResultView(const QString &plugin_id, QWidget *parent) : QTreeView(parent)
{
this->setFrameShape(QFrame::NoFrame);
this->viewport()->setAutoFillBackground(false);
this->setRootIsDecorated(false);
this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
this->setSelectionMode(QAbstractItemView::SingleSelection);
this->setHeaderHidden(true);
m_model = new SearchResultModel(plugin_id);
this->setModel(m_model);
initConnections();
m_plugin_id = plugin_id;
}
bool ResultView::isSelected()
{
return m_is_selected;
}
void ResultView::clearSelectedRow()
{
if (!m_is_selected) {
this->blockSignals(true);
this->clearSelection();
this->blockSignals(false);
}
}
void ResultView::initConnections()
{
connect(this, &ResultView::startSearch, m_model, &SearchResultModel::startSearch);
connect(this, &ResultView::stopSearch, m_model, &SearchResultModel::stopSearch);
connect(this->selectionModel(), &QItemSelectionModel::selectionChanged, this, [ = ](const QItemSelection & selected, const QItemSelection & deselected) {
//NEW_TODO 处理选中事件
m_is_selected = true;
Q_EMIT this->currentRowChanged(m_plugin_id, m_model->getInfo(this->currentIndex()));
m_is_selected = false;
if(!selected.isEmpty()) {
QRegion region = visualRegionForSelection(selected);
QRect rect = region.boundingRect();
// Q_EMIT this->currentSelectPos(mapToParent(rect.topLeft()));
}
});
connect(this, &ResultView::activated, this, [ = ](const QModelIndex & index) {
//NEW_TODO 处理双击打开事件
});
}

View File

@ -0,0 +1,63 @@
#ifndef RESULTVIEW_H
#define RESULTVIEW_H
#include <QTreeView>
#include <QVBoxLayout>
#include <QLabel>
#include "search-result-model.h"
#include "show-more-label.h"
#include "title-label.h"
namespace Zeeker {
class ResultView : public QTreeView
{
Q_OBJECT
public:
ResultView(const QString &plugin_id, QWidget *parent = nullptr);
~ResultView() = default;
bool isSelected();
public Q_SLOTS:
void clearSelectedRow();
private:
void initConnections();
SearchResultModel * m_model = nullptr;
QString m_plugin_id;
bool m_is_selected = false;
Q_SIGNALS:
void startSearch(const QString &);
void stopSearch();
void currentRowChanged(const QString &, const SearchPluginIface::ResultInfo&);
};
class ResultWidget : public QWidget
{
Q_OBJECT
public:
ResultWidget(const QString &plugin_id, QWidget *parent = nullptr);
~ResultWidget() = default;
QString pluginId();
void setEnabled(const bool&);
private:
QString m_plugin_id;
bool m_enabled = true;
void initUi();
void initConnections();
QVBoxLayout * m_mainLyt = nullptr;
TitleLabel * m_titleLabel = nullptr;
ResultView * m_resultView = nullptr;
ShowMoreLabel * m_showMoreLabel = nullptr;
Q_SIGNALS:
void startSearch(const QString &);
void stopSearch();
void currentRowChanged(const QString &, const SearchPluginIface::ResultInfo&);
void clearSelectedRow();
};
}
#endif // RESULTVIEW_H

7
frontend/view/view.pri Normal file
View File

@ -0,0 +1,7 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/result-view.h \
SOURCES += \
$$PWD/result-view.cpp \

View File

@ -0,0 +1,200 @@
/*
* KWin Style UKUI
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: Yue Lan <lanyue@kylinos.cn>
*
*/
#include "xatom-helper.h"
#include <limits.h>
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <NETWM>
static XAtomHelper *global_instance = nullptr;
XAtomHelper *XAtomHelper::getInstance() {
if(!global_instance)
global_instance = new XAtomHelper;
return global_instance;
}
bool XAtomHelper::isFrameLessWindow(int winId) {
auto hints = getInstance()->getWindowMotifHint(winId);
if(hints.flags == MWM_HINTS_DECORATIONS && hints.functions == 1) {
return true;
}
return false;
}
bool XAtomHelper::isWindowDecorateBorderOnly(int winId) {
return isWindowMotifHintDecorateBorderOnly(getInstance()->getWindowMotifHint(winId));
}
bool XAtomHelper::isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint) {
bool isDeco = false;
if(hint.flags & MWM_HINTS_DECORATIONS && hint.flags != MWM_HINTS_DECORATIONS) {
if(hint.decorations == MWM_DECOR_BORDER)
isDeco = true;
}
return isDeco;
}
bool XAtomHelper::isUKUICsdSupported() {
// fixme:
return false;
}
bool XAtomHelper::isUKUIDecorationWindow(int winId) {
if(m_ukuiDecorationAtion == None)
return false;
Atom type;
int format;
ulong nitems;
ulong bytes_after;
uchar *data;
bool isUKUIDecoration = false;
XGetWindowProperty(QX11Info::display(), winId, m_ukuiDecorationAtion,
0, LONG_MAX, false,
m_ukuiDecorationAtion, &type,
&format, &nitems,
&bytes_after, &data);
if(type == m_ukuiDecorationAtion) {
if(nitems == 1) {
isUKUIDecoration = data[0];
}
}
return isUKUIDecoration;
}
UnityCorners XAtomHelper::getWindowBorderRadius(int winId) {
UnityCorners corners;
Atom type;
int format;
ulong nitems;
ulong bytes_after;
uchar *data;
if(m_unityBorderRadiusAtom != None) {
XGetWindowProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom,
0, LONG_MAX, false,
XA_CARDINAL, &type,
&format, &nitems,
&bytes_after, &data);
if(type == XA_CARDINAL) {
if(nitems == 4) {
corners.topLeft = static_cast<ulong>(data[0]);
corners.topRight = static_cast<ulong>(data[1 * sizeof(ulong)]);
corners.bottomLeft = static_cast<ulong>(data[2 * sizeof(ulong)]);
corners.bottomRight = static_cast<ulong>(data[3 * sizeof(ulong)]);
}
XFree(data);
}
}
return corners;
}
void XAtomHelper::setWindowBorderRadius(int winId, const UnityCorners &data) {
if(m_unityBorderRadiusAtom == None)
return;
ulong corners[4] = {data.topLeft, data.topRight, data.bottomLeft, data.bottomRight};
XChangeProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL,
32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &corners, sizeof(corners) / sizeof(corners[0]));
}
void XAtomHelper::setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight) {
if(m_unityBorderRadiusAtom == None)
return;
ulong corners[4] = {(ulong)topLeft, (ulong)topRight, (ulong)bottomLeft, (ulong)bottomRight};
XChangeProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL,
32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &corners, sizeof(corners) / sizeof(corners[0]));
}
void XAtomHelper::setUKUIDecoraiontHint(int winId, bool set) {
if(m_ukuiDecorationAtion == None)
return;
XChangeProperty(QX11Info::display(), winId, m_ukuiDecorationAtion, m_ukuiDecorationAtion, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &set, 1);
}
void XAtomHelper::setWindowMotifHint(int winId, const MotifWmHints &hints) {
if(m_unityBorderRadiusAtom == None)
return;
XChangeProperty(QX11Info::display(), winId, m_motifWMHintsAtom, m_motifWMHintsAtom,
32, XCB_PROP_MODE_REPLACE, (const unsigned char *)&hints, sizeof(MotifWmHints) / sizeof(ulong));
}
MotifWmHints XAtomHelper::getWindowMotifHint(int winId) {
MotifWmHints hints;
if(m_unityBorderRadiusAtom == None)
return hints;
uchar *data;
Atom type;
int format;
ulong nitems;
ulong bytes_after;
XGetWindowProperty(QX11Info::display(), winId, m_motifWMHintsAtom,
0, sizeof(MotifWmHints) / sizeof(long), false, AnyPropertyType, &type,
&format, &nitems, &bytes_after, &data);
if(type == None) {
return hints;
} else {
hints = *(MotifWmHints *)data;
XFree(data);
}
return hints;
}
XAtomHelper::XAtomHelper(QObject *parent) : QObject(parent) {
if(!QX11Info::isPlatformX11())
return;
m_motifWMHintsAtom = XInternAtom(QX11Info::display(), "_MOTIF_WM_HINTS", true);
m_unityBorderRadiusAtom = XInternAtom(QX11Info::display(), "_UNITY_GTK_BORDER_RADIUS", false);
m_ukuiDecorationAtion = XInternAtom(QX11Info::display(), "_KWIN_UKUI_DECORAION", false);
}
Atom XAtomHelper::registerUKUICsdNetWmSupportAtom() {
// fixme:
return None;
}
void XAtomHelper::unregisterUKUICsdNetWmSupportAtom() {
// fixme:
}

View File

@ -0,0 +1,110 @@
/*
* KWin Style UKUI
*
* Copyright (C) 2020, 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 <https://www.gnu.org/licenses/>.
*
* Authors: Yue Lan <lanyue@kylinos.cn>
*
*/
#ifndef XATOMHELPER_H
#define XATOMHELPER_H
#include <QObject>
#include <X11/Xlib.h>
#include <NETWM>
struct UnityCorners {
ulong topLeft = 0;
ulong topRight = 0;
ulong bottomLeft = 0;
ulong bottomRight = 0;
};
typedef struct {
ulong flags = 0;
ulong functions = 0;
ulong decorations = 0;
long input_mode = 0;
ulong status = 0;
} MotifWmHints, MwmHints;
#define MWM_HINTS_FUNCTIONS (1L << 0)
#define MWM_HINTS_DECORATIONS (1L << 1)
#define MWM_HINTS_INPUT_MODE (1L << 2)
#define MWM_HINTS_STATUS (1L << 3)
#define MWM_FUNC_ALL (1L << 0)
#define MWM_FUNC_RESIZE (1L << 1)
#define MWM_FUNC_MOVE (1L << 2)
#define MWM_FUNC_MINIMIZE (1L << 3)
#define MWM_FUNC_MAXIMIZE (1L << 4)
#define MWM_FUNC_CLOSE (1L << 5)
#define MWM_DECOR_ALL (1L << 0)
#define MWM_DECOR_BORDER (1L << 1)
#define MWM_DECOR_RESIZEH (1L << 2)
#define MWM_DECOR_TITLE (1L << 3)
#define MWM_DECOR_MENU (1L << 4)
#define MWM_DECOR_MINIMIZE (1L << 5)
#define MWM_DECOR_MAXIMIZE (1L << 6)
#define MWM_INPUT_MODELESS 0
#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
#define MWM_INPUT_SYSTEM_MODAL 2
#define MWM_INPUT_FULL_APPLICATION_MODAL 3
#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
#define MWM_TEAROFF_WINDOW (1L<<0)
namespace UKUI {
class Decoration;
}
class XAtomHelper : public QObject {
// friend class UKUI::Decoration;
Q_OBJECT
public:
static XAtomHelper *getInstance();
static bool isFrameLessWindow(int winId);
static bool isWindowDecorateBorderOnly(int winId);
static bool isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint);
bool isUKUICsdSupported();
bool isUKUIDecorationWindow(int winId);
UnityCorners getWindowBorderRadius(int winId);
void setWindowBorderRadius(int winId, const UnityCorners &data);
void setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight);
void setUKUIDecoraiontHint(int winId, bool set = true);
void setWindowMotifHint(int winId, const MotifWmHints &hints);
MotifWmHints getWindowMotifHint(int winId);
private:
explicit XAtomHelper(QObject *parent = nullptr);
Atom registerUKUICsdNetWmSupportAtom();
void unregisterUKUICsdNetWmSupportAtom();
Atom m_motifWMHintsAtom = None;
Atom m_unityBorderRadiusAtom = None;
Atom m_ukuiDecorationAtion = None;
};
#endif // XATOMHELPER_H

7
frontend/xatom/xatom.pri Normal file
View File

@ -0,0 +1,7 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/xatom-helper.h \
SOURCES += \
$$PWD/xatom-helper.cpp \

View File

@ -43,7 +43,7 @@ void TitleLabel::paintEvent(QPaintEvent * event) {
QRect rect = this->rect(); QRect rect = this->rect();
p.setRenderHint(QPainter::Antialiasing); // 反锯齿; p.setRenderHint(QPainter::Antialiasing); // 反锯齿;
p.setBrush(opt.palette.color(QPalette::Text)); p.setBrush(opt.palette.color(QPalette::Text));
p.setOpacity(0.06); p.setOpacity(0.04);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.drawRoundedRect(rect, 0, 0); p.drawRoundedRect(rect, 0, 0);
return QLabel::paintEvent(event); return QLabel::paintEvent(event);

View File

@ -2,6 +2,7 @@ TEMPLATE = subdirs
SUBDIRS += $$PWD/libchinese-segmentation \ SUBDIRS += $$PWD/libchinese-segmentation \
$$PWD/libsearch \ $$PWD/libsearch \
$$PWD/src \ $$PWD/src \
$$PWD/frontend \
$$PWD/ukuisearch-systemdbus $$PWD/ukuisearch-systemdbus
# The following define makes your compiler emit warnings if you use # The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings # any Qt feature that has been marked deprecated (the exact warnings
@ -17,5 +18,8 @@ DEFINES += QT_DEPRECATED_WARNINGS
libsearch.depends += libchinese-segmentation libsearch.depends += libchinese-segmentation
src.depends = libsearch src.depends = libsearch
CONFIG += ordered CONFIG += ordered \
qt
QT += widgets