Skip to content

Commit

Permalink
fix: Fix block issue by many schedules
Browse files Browse the repository at this point in the history
If there are a lot of schedules(recurs), then the UI will be blocked and do any operation become very slow. The root reason is too many json string to response from Dbus.

Log: Fix block issue by many schedules.
Bug: https://pms.uniontech.com/bug-view-274791.html
  • Loading branch information
re2zero authored and myml committed Nov 26, 2024
1 parent 8d11e3b commit e47a5db
Show file tree
Hide file tree
Showing 23 changed files with 217 additions and 51 deletions.
4 changes: 2 additions & 2 deletions calendar-client/src/customWidget/colorseletorwidget.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand Down Expand Up @@ -122,7 +122,7 @@ void ColorSeletorWidget::setSelectedColorById(int colorId)
} else {
++colorId;
}
if (m_colorGroup->buttons().size() > 0) {
if (m_colorGroup->buttons().size() > colorId) {
m_colorGroup->buttons().at(colorId)->click();
}
}
Expand Down
6 changes: 3 additions & 3 deletions calendar-client/src/dataManage/accountitem.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand Down Expand Up @@ -315,8 +315,8 @@ void AccountItem::deleteSchedulesByTypeID(const QString &typeID, CallbackFunc ca

void AccountItem::querySchedulesWithParameter(const int year, CallbackFunc callback)
{
QDateTime start = QDate(year - 1, 12, 1).startOfDay();
QDateTime end = QDate(year + 1, 1, 31).startOfDay();
QDateTime start = QDateTime(QDate(year, 1, 1));
QDateTime end = QDateTime(QDate(year, 12, 31));
querySchedulesWithParameter(start, end, callback);
}

Expand Down
6 changes: 3 additions & 3 deletions calendar-client/src/dbus/dbusaccountrequest.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand Down Expand Up @@ -282,12 +282,12 @@ void DbusAccountRequest::slotCallFinished(CDBusPendingCallWatcher *call)
} else if (call->getmember() == "querySchedulesWithParameter") {
QDBusPendingReply<QString> reply = *call;
QString str = reply.argumentAt<0>();
QMap<QDate, DSchedule::List> map = DSchedule::fromMapString(str);
QMap<QDate, DSchedule::List> map = DSchedule::fromQueryResult(str);
emit signalGetScheduleListFinish(map);
} else if (call->getmember() == "searchSchedulesWithParameter") {
QDBusPendingReply<QString> reply = *call;
QString str = reply.argumentAt<0>();
QMap<QDate, DSchedule::List> map = DSchedule::fromMapString(str);
QMap<QDate, DSchedule::List> map = DSchedule::fromQueryResult(str);
emit signalSearchScheduleListFinish(map);
} else if (call->getmember() == "getSysColors") {
QDBusPendingReply<QString> reply = *call;
Expand Down
8 changes: 7 additions & 1 deletion calendar-common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-strong -z noexecstack
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
aux_source_directory(src BASESTRUCT_SRCS)
aux_source_directory(src/huangliData BASESTRUCT_SRCS_HUANGLI)
aux_source_directory(src/lunarandfestival BASESTRUCT_SRCS_NONGLI)
aux_source_directory(src/pinyin BASESTRUCT_SRCS_PINYIN)
link_libraries(${Qt5CORE_LIBRARIES} ${Qt5DBus_LIBRARIES})

add_library(${PROJECT_NAME} STATIC ${BASESTRUCT_SRCS} ${BASESTRUCT_SRCS_HUANGLI})
add_library(${PROJECT_NAME} STATIC ${BASESTRUCT_SRCS}
${BASESTRUCT_SRCS_HUANGLI}
${BASESTRUCT_SRCS_NONGLI}
${BASESTRUCT_SRCS_PINYIN}
)
target_include_directories(${PROJECT_NAME} PUBLIC ../3rdparty/kcalendarcore/src)

target_link_libraries(${PROJECT_NAME}
Expand Down
188 changes: 187 additions & 1 deletion calendar-common/src/dschedule.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "dschedule.h"
#include "commondef.h"
#include "lunarandfestival/lunardateinfo.h"

#include "icalformat.h"
#include "memorycalendar.h"
Expand Down Expand Up @@ -343,6 +344,191 @@ QString DSchedule::toMapString(const QMap<QDate, DSchedule::List> &scheduleMap)
return QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Compact));
}

QPair<QString, DSchedule::List> DSchedule::fromListString(const QString &json)
{
QPair<QString, DSchedule::List> schedulePair;
QJsonParseError jsonError;
QJsonDocument jsonDoc(QJsonDocument::fromJson(json.toLocal8Bit(), &jsonError));
if (jsonError.error != QJsonParseError::NoError) {
qCWarning(CommonLogger) << "error:" << jsonError.errorString();
return schedulePair;
}

QJsonObject jsonObj = jsonDoc.object();
DSchedule::List scheduleList;
if (jsonObj.contains("query")) {
schedulePair.first = jsonObj.value("query").toString();
}
if (jsonObj.contains("schedules")) {
QJsonArray jsonArray = jsonObj.value("schedules").toArray();
foreach (auto scheduleValue, jsonArray) {
QString scheduleStr = scheduleValue.toString();
DSchedule::Ptr schedule = DSchedule::Ptr(new DSchedule);
DSchedule::fromJsonString(schedule, scheduleStr);
scheduleList.append(schedule);
}
}
schedulePair.second = scheduleList;

return schedulePair;
}

QString DSchedule::toListString(const QString &query, const DSchedule::List &scheduleList)
{
QJsonObject jsonObj;
jsonObj.insert("query", query);
QJsonArray jsonArray;
foreach (auto &schedule, scheduleList) {
QString scheduleStr;
DSchedule::toJsonString(schedule, scheduleStr);
jsonArray.append(scheduleStr);
}
jsonObj.insert("schedules", jsonArray);


QJsonDocument jsonDoc;
jsonDoc.setObject(jsonObj);
return QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Compact));
}

void DSchedule::expendRecurrence(DSchedule::Map &scheduleMap, const DSchedule::Ptr &schedule, const QDateTime &dtStart, const QDateTime &dtEnd)
{
QDateTime queryDtStart = dtStart;
//如果日程为全天日程,则查询的开始时间设置为0点,因为全天日程的开始和结束时间都是0点
if(schedule->allDay()){
queryDtStart.setTime(QTime(0,0,0));
}
if (schedule->recurs()) {
//获取日程的开始结束时间差
qint64 interval = schedule->dtStart().secsTo(schedule->dtEnd());
QList<QDateTime> dtList = schedule->recurrence()->timesInInterval(queryDtStart, dtEnd);
foreach (auto &dt, dtList) {
QDateTime scheduleDtEnd = dt.addSecs(interval);
DSchedule::Ptr newSchedule = DSchedule::Ptr(schedule->clone());
newSchedule->setDtStart(dt);
newSchedule->setDtEnd(scheduleDtEnd);

//只有重复日程设置RecurrenceId
if (schedule->dtStart() != dt) {
newSchedule->setRecurrenceId(dt);
}
scheduleMap[dt.date()].append(newSchedule);
}
} else {
if (!(schedule->dtStart() > dtEnd || schedule->dtEnd() < queryDtStart)) {
scheduleMap[schedule->dtStart().date()].append(schedule);
}
}
}

QMap<QDate, DSchedule::List> DSchedule::convertSchedules(const DScheduleQueryPar::Ptr &queryPar, const DSchedule::List &scheduleList)
{
QDateTime dtStart = queryPar->dtStart();
QDateTime dtEnd = queryPar->dtEnd();
bool extend = queryPar->queryType() == DScheduleQueryPar::Query_None;

QMap<QDate, DSchedule::List> scheduleMap;
foreach (auto &schedule, scheduleList) {
//获取日程的开始结束时间差
qint64 interval = schedule->dtStart().secsTo(schedule->dtEnd());
//如果存在重复日程
if (schedule->recurs()) {
//如果为农历日程
if (schedule->lunnar()) {
//农历重复日程计算
LunarDateInfo lunardate(schedule->recurrence()->defaultRRuleConst(), interval);

QMap<int, QDate> ruleStartDate = lunardate.getRRuleStartDate(dtStart.date(), dtEnd.date(), schedule->dtStart().date());

QDateTime recurDateTime;
recurDateTime.setTime(schedule->dtStart().time());
QDateTime copyEnd;
QMap<int, QDate>::ConstIterator iter = ruleStartDate.constBegin();
for (; iter != ruleStartDate.constEnd(); iter++) {
recurDateTime.setDate(iter.value());
//如果在忽略时间列表中,则忽略
if (schedule->recurrence()->exDateTimes().contains(recurDateTime))
continue;
copyEnd = recurDateTime.addSecs(interval);
DSchedule::Ptr newSchedule = DSchedule::Ptr(new DSchedule(*schedule.data()));
newSchedule->setDtStart(recurDateTime);
newSchedule->setDtEnd(copyEnd);
//只有重复日程设置RecurrenceId
if (schedule->dtStart() != recurDateTime) {
newSchedule->setRecurrenceId(recurDateTime);
}
scheduleMap[recurDateTime.date()].append(newSchedule);
}
} else {
//非农历日程
expendRecurrence(scheduleMap, schedule, dtStart, dtEnd);
}
} else {
//普通日程
//如果在查询时间范围内
QDateTime queryDtStart = dtStart;
//如果日程为全天日程,则查询的开始时间设置为0点,因为全天日程的开始和结束时间都是0点
if(schedule->allDay()){
queryDtStart.setTime(QTime(0,0,0));
}
if (!(schedule->dtEnd() < queryDtStart || schedule->dtStart() > dtEnd)) {
if (extend && schedule->isMultiDay()) {
//需要扩展的天数
int extenddays = static_cast<int>(schedule->dtStart().daysTo(schedule->dtEnd()));
for (int i = 0; i <= extenddays; ++i) {
//如果扩展的日期在查询范围内则添加,否则退出
if(scheduleMap.contains(schedule->dtStart().date().addDays(i))){
scheduleMap[schedule->dtStart().date().addDays(i)].append(schedule);
} else {
break;
}
}
} else {
scheduleMap[schedule->dtStart().date()].append(schedule);
}
}
}
}

//如果为查询前N个日程,则取前N个日程
if (queryPar->queryType() == DScheduleQueryPar::Query_Top) {
int scheduleNum = 0;
DSchedule::Map filterSchedule;
DSchedule::Map::const_iterator iter = scheduleMap.constBegin();
for (; iter != scheduleMap.constEnd(); ++iter) {
if (iter.value().size() == 0) {
continue;
}
if (scheduleNum + iter.value().size() > queryPar->queryTop()) {
DSchedule::List scheduleList;
int residuesNum = queryPar->queryTop() - scheduleNum;
for (int i = 0; i < residuesNum; ++i) {
scheduleList.append(iter.value().at(i));
}
filterSchedule[iter.key()] = scheduleList;
} else {
filterSchedule[iter.key()] = iter.value();
}
}
scheduleMap = filterSchedule;
}

return scheduleMap;
}

QMap<QDate, DSchedule::List> DSchedule::fromQueryResult(const QString &query)
{
QMap<QDate, DSchedule::List> scheduleMap;
QPair<QString, DSchedule::List> pair = fromListString(query);
DScheduleQueryPar::Ptr queryPar = DScheduleQueryPar::fromJsonString(pair.first);
if (queryPar.isNull()) {
return scheduleMap;
}

scheduleMap = DSchedule::convertSchedules(queryPar, pair.second);
return scheduleMap;
}

bool operator==(const DSchedule::Ptr &s1, const DSchedule::Ptr &s2)
{
return s1.isNull() || s2.isNull() ? s1.isNull() && s2.isNull() : s1->instanceIdentifier() == s2->instanceIdentifier();
Expand Down
8 changes: 8 additions & 0 deletions calendar-common/src/dschedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define DSCHEDULE_H

#include "event.h"
#include "dschedulequerypar.h"

#include <QString>
#include <QDebug>
Expand Down Expand Up @@ -92,6 +93,13 @@ class DSchedule : public KCalendarCore::Event
static QMap<QDate, DSchedule::List> fromMapString(const QString &json);
static QString toMapString(const QMap<QDate, DSchedule::List> &scheduleMap);

static QPair<QString, DSchedule::List> fromListString(const QString &json);
static QString toListString(const QString &query, const DSchedule::List &scheduleList);

static void expendRecurrence(DSchedule::Map &scheduleMap, const DSchedule::Ptr &schedule, const QDateTime &dtStart, const QDateTime &dtEnd);
static QMap<QDate, DSchedule::List> convertSchedules(const DScheduleQueryPar::Ptr &queryPar, const DSchedule::List &scheduleList);
static QMap<QDate, DSchedule::List> fromQueryResult(const QString &query);

private:
QMap<int, AlarmType> getAlarmMap();

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
44 changes: 5 additions & 39 deletions calendar-service/src/calendarDataManager/daccountmodule.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand All @@ -7,8 +7,8 @@
#include "dscheduletype.h"
#include "dschedulequerypar.h"
#include "memorycalendar.h"
#include "lunardateinfo.h"
#include "lunarmanager.h"
#include "lunarandfestival/lunardateinfo.h"
#include "lunarandfestival/lunarmanager.h"
#include "dbus/dbusuiopenschedule.h"
#include "dalarmmanager.h"
#include "syncfilemanage.h"
Expand Down Expand Up @@ -442,16 +442,7 @@ QString DAccountModule::querySchedulesWithParameter(const QString &params)
if (schedule.isNull()) {
return QString();
}
QMap<QDate, DSchedule::List> m_scheduleMap;
//相差多少天
int days = static_cast<int>(queryPar->dtStart().daysTo(queryPar->dtEnd()));
for (int i = 0; i <= days; ++i) {
DSchedule::List scheduleList;
m_scheduleMap[queryPar->dtStart().addDays(i).date()] = scheduleList;
}
extendRecurrence(m_scheduleMap, schedule, queryPar->dtStart(), queryPar->dtEnd(), false);
return DSchedule::toMapString(m_scheduleMap);

scheduleList.append(schedule);
} else {
scheduleList = m_accountDB->querySchedulesByKey(queryPar->key());
}
Expand All @@ -462,32 +453,7 @@ QString DAccountModule::querySchedulesWithParameter(const QString &params)
scheduleList.append(getFestivalSchedule(queryPar->dtStart(), queryPar->dtEnd(), queryPar->key()));
}

//获取一定范围内的日程
QMap<QDate, DSchedule::List> scheduleMap = getScheduleTimesOn(queryPar->dtStart(), queryPar->dtEnd(), scheduleList, extend);

//如果为查询前N个日程,则取前N个日程
if (queryPar->queryType() == DScheduleQueryPar::Query_Top) {
int scheduleNum = 0;
DSchedule::Map filterSchedule;
DSchedule::Map::const_iterator iter = scheduleMap.constBegin();
for (; iter != scheduleMap.constEnd(); ++iter) {
if (iter.value().size() == 0) {
continue;
}
if (scheduleNum + iter.value().size() > queryPar->queryTop()) {
DSchedule::List scheduleList;
int residuesNum = queryPar->queryTop() - scheduleNum;
for (int i = 0; i < residuesNum; ++i) {
scheduleList.append(iter.value().at(i));
}
filterSchedule[iter.key()] = scheduleList;
} else {
filterSchedule[iter.key()] = iter.value();
}
}
scheduleMap = filterSchedule;
}
return DSchedule::toMapString(scheduleMap);
return DSchedule::toListString(params, scheduleList);
}

DSchedule::List DAccountModule::getRemindScheduleList(const QDateTime &dtStart, const QDateTime &dtEnd)
Expand Down
4 changes: 2 additions & 2 deletions calendar-service/src/dbmanager/dhuanglidatabase.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand All @@ -7,7 +7,7 @@

#include "ddatabase.h"
#include "huangliData/lunardatastruct.h"
#include "lunarandfestival.h"
#include "lunarandfestival/lunarandfestival.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QSettings>
Expand Down

0 comments on commit e47a5db

Please sign in to comment.