Skip to content

Commit fb55647

Browse files
committed
refactor: assign appgroup data keep synced
之前的 groupmanager 管理分组内 item 的逻辑问题比较多,依次处理后仍然发现行为不符合预期,故决定直接复用启动器现有的分组管理逻辑(略有调整以对接原有 dconfig 配置)。 此提交起,应用信息即会自动分配分组(新应用分配到顶层分组,即编号 0 的文件夹,原有已知存在分组的应用保持不变),应用模型变动时即存储信息回 dconfig。 Log:
1 parent 6611e47 commit fb55647

File tree

9 files changed

+525
-98
lines changed

9 files changed

+525
-98
lines changed

applets/dde-apps/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ add_library(dde-apps SHARED ${DBUS_INTERFACES}
5353
appslaunchtimes.h
5454
categoryutils.cpp
5555
categoryutils.h
56+
itemspage.cpp
57+
itemspage.h
5658
)
5759

5860
target_link_libraries(dde-apps PRIVATE

applets/dde-apps/amappitemmodel.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
#include <DUtil>
1212
#include <QtConcurrent>
13-
#include <tuple>
1413

1514
Q_LOGGING_CATEGORY(appsLog, "dde.shell.dde-apps.amappitemmodel")
1615

applets/dde-apps/appgroup.cpp

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "appgroup.h"
66
#include "appgroupmanager.h"
77
#include "appitemmodel.h"
8+
#include "itemspage.h"
89

910
#include <QLoggingCategory>
1011
#include <algorithm>
@@ -14,44 +15,47 @@ Q_LOGGING_CATEGORY(appGroupLog, "org.deepin.ds.dde-apps.appgroup")
1415
namespace apps {
1516
AppGroup::AppGroup(const QString &groupId, const QString &name, const QList<QStringList> &appIDs)
1617
: AppItem(groupId, AppItemModel::FolderItemType)
18+
, m_itemsPage(new ItemsPage(name, groupId == QStringLiteral("internal/folder/0") ? (4 * 8) : (3 * 4)))
1719
{
18-
if (groupId == QStringLiteral("internal/folder/0")) {
19-
setItemsPerPage(4 * 8);
20-
} else {
21-
setItemsPerPage(3 * 4);
20+
setItemsPerPage(m_itemsPage->maxItemCountPerPage());
21+
setAppName(m_itemsPage->name());
22+
// folder id is a part of its groupId: "internal/folder/{folderId}"
23+
setFolderId(groupId.section('/', -1).toInt());
24+
25+
for (const QStringList &items : appIDs) {
26+
m_itemsPage->appendPage(items);
2227
}
23-
setAppName(name);
24-
setAppItems(appIDs);
2528
}
2629

27-
QList<QStringList> AppGroup::appItems() const
30+
AppGroup::~AppGroup()
2831
{
29-
QList<QStringList> res;
30-
auto pages = data(AppGroupManager::GroupAppItemsRole).toList();
31-
std::transform(pages.begin(), pages.end(), std::back_inserter(res), [](const QVariant &data) {
32-
return data.toStringList();
33-
});
32+
delete m_itemsPage;
33+
}
3434

35-
return res;
35+
int AppGroup::folderId() const
36+
{
37+
return data(AppGroupManager::GroupIdRole).toInt();
3638
}
3739

38-
void AppGroup::setAppItems(const QList<QStringList> &items)
40+
QList<QStringList> AppGroup::pages() const
3941
{
40-
QVariantList data;
41-
std::transform(items.begin(), items.end(), std::back_inserter(data), [](const QStringList &c) {
42-
QVariantList tmp;
43-
std::transform(c.begin(), c.end(), std::back_inserter(tmp), [](const QString &s) {
44-
return s;
45-
});
46-
return tmp;
47-
});
48-
return setData(data, AppGroupManager::GroupAppItemsRole);
42+
return m_itemsPage->allPagedItems();
43+
}
44+
45+
ItemsPage *AppGroup::itemsPage()
46+
{
47+
return m_itemsPage;
4948
}
5049

5150
void AppGroup::setItemsPerPage(int number)
5251
{
5352
return setData(number, AppGroupManager::GroupItemsPerPageRole);
5453
}
5554

55+
void AppGroup::setFolderId(int folderId)
56+
{
57+
setData(folderId, AppGroupManager::GroupIdRole);
58+
}
59+
5660
}
5761

applets/dde-apps/appgroup.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,22 @@
66

77
#include "appitem.h"
88

9+
class ItemsPage;
910
namespace apps {
1011
class AppGroup : public AppItem
1112
{
1213
public:
1314
explicit AppGroup(const QString &groupId, const QString &name, const QList<QStringList> &appItemIDs);
15+
~AppGroup() override;
1416

15-
QString name() const;
16-
void setName(const QString &name);
17-
18-
QList<QStringList> appItems() const;
19-
void setAppItems(const QList<QStringList> &items);
17+
int folderId() const;
18+
QList<QStringList> pages() const;
19+
ItemsPage * itemsPage();
2020

21+
private:
2122
void setItemsPerPage(int number);
23+
void setFolderId(int folderId);
24+
25+
ItemsPage * m_itemsPage;
2226
};
2327
}

applets/dde-apps/appgroupmanager.cpp

Lines changed: 126 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
#include "appgroupmanager.h"
66
#include "appgroup.h"
7+
#include "itemspage.h"
78
#include "amappitemmodel.h"
89

9-
#include <QtConcurrent>
10+
#define TOPLEVEL_FOLDERID 0
1011

1112
namespace apps {
1213

@@ -21,10 +22,18 @@ AppGroupManager::AppGroupManager(AMAppItemModel * referenceModel, QObject *paren
2122

2223
loadAppGroupInfo();
2324

25+
connect(m_referenceModel, &AMAppItemModel::rowsInserted, this, [this](){
26+
onReferenceModelChanged();
27+
saveAppGroupInfo();
28+
});
29+
connect(m_referenceModel, &AMAppItemModel::rowsRemoved, this, [this](){
30+
onReferenceModelChanged();
31+
saveAppGroupInfo();
32+
});
2433
connect(m_dumpTimer, &QTimer::timeout, this, [this](){
25-
dumpAppGroupInfo();
34+
saveAppGroupInfo();
2635
});
27-
connect(this, &AppGroupManager::dataChanged, this, &AppGroupManager::dumpAppGroupInfo);
36+
connect(this, &AppGroupManager::dataChanged, this, &AppGroupManager::saveAppGroupInfo);
2837
}
2938

3039
QVariant AppGroupManager::data(const QModelIndex &index, int role) const
@@ -39,114 +48,167 @@ QVariant AppGroupManager::data(const QModelIndex &index, int role) const
3948
return QStandardItemModel::data(index, role);
4049
}
4150

42-
std::tuple<int, int, int> AppGroupManager::getAppGroupInfo(const QString &appId)
51+
// Find the item's location. If folderId is -1, search all folders.
52+
std::tuple<int, int, int> AppGroupManager::findItem(const QString &appId, int folderId)
4353
{
44-
std::tuple<int, int, int> res = {-1, -1, -1};
45-
do {
46-
int groupPos, pagePos;
47-
std::tie(groupPos, pagePos) = m_map.value(appId, std::make_tuple<int, int>(-1, -1));
48-
auto groupIndex = index(groupPos, 0);
49-
50-
if (!groupIndex.isValid())
51-
break;
54+
int page, idx;
5255

53-
auto pages = groupIndex.data(GroupAppItemsRole).toList();
54-
if (pages.length() == 0)
55-
break;
56-
57-
auto items = pages.value(pagePos).toStringList();
58-
if (items.length() == 0)
59-
break;
60-
61-
auto itemPos = items.indexOf(appId);
62-
res = std::make_tuple(groupPos, pagePos, itemPos);
63-
} while (0);
56+
for (int i = 0; i < rowCount(); i++) {
57+
auto group = static_cast<AppGroup*>(itemFromIndex(index(i, 0)));
58+
if (folderId >= 0 && group->folderId() != folderId) {
59+
continue;
60+
}
61+
std::tie(page, idx) = group->itemsPage()->findItem(appId);
62+
if (page != -1) {
63+
return std::make_tuple(group->folderId(), page, idx);
64+
}
65+
}
6466

65-
return res;
67+
return std::make_tuple(-1, -1, -1);
6668
}
6769

68-
void AppGroupManager::setAppGroupInfo(const QString &appId, std::tuple<int, int, int> groupInfo)
70+
void AppGroupManager::appendItemToGroup(const QString &appId, int groupId)
6971
{
70-
int groupPos, pagePos, itemPos;
71-
std::tie(groupPos, pagePos, itemPos) = groupInfo;
72-
73-
auto groupIndex = index(groupPos, 0);
74-
if (!groupIndex.isValid()) {
75-
return;
76-
}
77-
78-
auto appItems = groupIndex.data(GroupAppItemsRole).value<QList<QStringList>>();
79-
int groupItemsPerPage = groupIndex.data(GroupItemsPerPageRole).toInt();
80-
81-
for (int i = pagePos; i < appItems.length() - 1; i++) {
82-
appItems[i].insert(itemPos, appId);
83-
m_map.insert(appId, std::make_tuple(groupPos, pagePos));
72+
auto folder = group(groupId);
73+
Q_CHECK_PTR(folder);
74+
folder->itemsPage()->appendItem(appId);
75+
}
8476

85-
// 本页最后一位元素插入到下页
86-
if (appItems[i].length() > groupItemsPerPage) {
87-
auto item = appItems[i].takeLast();
77+
bool AppGroupManager::removeItemFromGroup(const QString &appId, int groupId)
78+
{
79+
auto folder = group(groupId);
80+
Q_CHECK_PTR(folder);
81+
return folder->itemsPage()->removeItem(appId);
82+
}
8883

89-
appItems[i + 1].insert(0, item);
90-
m_map.insert(item, std::make_tuple(groupPos, i + 1));
84+
QModelIndex AppGroupManager::groupIndexById(int groupId)
85+
{
86+
for (int i = 0; i < rowCount(); i++) {
87+
auto groupIndex = index(i, 0);
88+
auto data = groupIndex.data(GroupIdRole);
89+
if (data.toInt() == groupId) {
90+
return groupIndex;
9191
}
9292
}
93+
return QModelIndex();
94+
}
9395

94-
if (appItems.length() > 1 && appItems.last().length() > groupItemsPerPage) {
95-
auto item = appItems.last().takeLast();
96-
appItems.append({item});
96+
AppGroup * AppGroupManager::group(int groupId)
97+
{
98+
auto groupIndex = groupIndexById(groupId);
99+
if (!groupIndex.isValid()) {
100+
return nullptr;
97101
}
102+
auto group = static_cast<AppGroup*>(itemFromIndex(groupIndex));
103+
return group;
104+
}
98105

99-
if (pagePos > appItems.length()) {
100-
appItems.append({appId});
106+
AppGroup * AppGroupManager::group(QModelIndex idx)
107+
{
108+
if (!idx.isValid()) {
109+
return nullptr;
101110
}
111+
auto group = static_cast<AppGroup*>(itemFromIndex(idx));
112+
return group;
113+
}
102114

115+
QVariantList AppGroupManager::fromListOfStringList(const QList<QStringList> & list)
116+
{
103117
QVariantList data;
104-
std::transform(appItems.begin(), appItems.end(), std::back_inserter(data), [](const QStringList &items) {
118+
std::transform(list.begin(), list.end(), std::back_inserter(data), [](const QStringList &items) {
105119
QVariantList tmp;
106120
std::transform(items.begin(), items.end(), std::back_inserter(tmp), [](const auto &item) {
107121
return QVariant::fromValue(item);
108122
});
109-
return tmp;
123+
return items;
110124
});
111125

112-
setData(groupIndex, data);
126+
return data;
127+
}
128+
129+
// On AM model changed, add newly installed apps to group (if any) and remove apps that are no longer exists.
130+
void AppGroupManager::onReferenceModelChanged()
131+
{
132+
// Avoid remove all existing records when first time (AM model is not ready).
133+
if (m_referenceModel->rowCount() == 0) {
134+
qDebug() << "referenceModel not ready, wait for next time";
135+
return;
136+
}
137+
138+
QSet<QString> appSet;
139+
for (int i = 0; i < m_referenceModel->rowCount(); i++) {
140+
const auto modelIndex = m_referenceModel->index(i, 0);
141+
const bool noDisplay = m_referenceModel->data(modelIndex, AppItemModel::NoDisplayRole).toBool();
142+
if (noDisplay) {
143+
continue;
144+
}
145+
const QString & desktopId = m_referenceModel->data(m_referenceModel->index(i, 0), AppItemModel::DesktopIdRole).toString();
146+
appSet.insert(desktopId);
147+
// add all existing ones if they are not already in
148+
int folder, page, idx;
149+
std::tie(folder, std::ignore, std::ignore) = findItem(desktopId);
150+
if (folder == -1) {
151+
appendItemToGroup(desktopId, TOPLEVEL_FOLDERID);
152+
}
153+
}
154+
155+
// remove all non-existing ones
156+
for (int i = rowCount() - 1; i >= 0; i--) {
157+
auto folder = group(index(i, 0));
158+
Q_CHECK_PTR(folder);
159+
folder->itemsPage()->removeItemsNotIn(appSet);
160+
// check if group itself is also empty, remove them too.
161+
if (folder->itemsPage()->itemCount() == 0 && folder->folderId() != TOPLEVEL_FOLDERID) {
162+
QString groupId = folder->appId();
163+
removeRow(i);
164+
removeItemFromGroup(groupId, TOPLEVEL_FOLDERID);
165+
}
166+
}
167+
168+
// TODO: emit datachanged signal?
169+
// TODO: save item arrangement to user data?
113170
}
114171

115172
void AppGroupManager::loadAppGroupInfo()
116173
{
117174
auto groups = m_config->value("Groups").toList();
175+
118176
for (int i = 0; i < groups.length(); i++) {
119177
auto group = groups[i].toMap();
120-
auto folderId = group.value("folderId", "").toString();
178+
auto groupId = group.value("groupId", "").toString();
121179
auto name = group.value("name", "").toString();
122180
auto pages = group.value("appItems", QVariantList()).toList();
123181
QList<QStringList> items;
124182

125183
for (int j = 0; j < pages.length(); j++) {
126184
auto page = pages[j].toStringList();
127185
items << page;
128-
std::for_each(page.begin(), page.end(), [this, i, j](const QString &item) {
129-
m_map.insert(item, std::make_tuple(i, j));
130-
});
131186
}
132187

133-
if (folderId.isEmpty()) {
134-
folderId = assignGroupId();
188+
if (groupId.isEmpty()) {
189+
groupId = assignGroupId();
135190
}
136-
auto p = new AppGroup(folderId, name, items);
191+
auto p = new AppGroup(groupId, name, items);
192+
appendRow(p);
193+
}
194+
195+
// always ensure top-level group exists
196+
if (rowCount() == 0) {
197+
auto p = new AppGroup(assignGroupId(), "Top Level", {});
198+
Q_ASSERT(p->folderId() == TOPLEVEL_FOLDERID);
137199
appendRow(p);
138200
}
139201
}
140202

141-
void AppGroupManager::dumpAppGroupInfo()
203+
void AppGroupManager::saveAppGroupInfo()
142204
{
143205
QVariantList list;
144206
for (int i = 0; i < rowCount(); i++) {
145-
auto data = index(i, 0);
207+
auto folder = group(index(i, 0));
146208
QVariantMap valueMap;
147-
valueMap.insert("name", data.data(AppItemModel::NameRole));
148-
valueMap.insert("folderId", data.data(AppItemModel::DesktopIdRole));
149-
valueMap.insert("appItems", data.data(GroupAppItemsRole));
209+
valueMap.insert("name", folder->data(AppItemModel::NameRole));
210+
valueMap.insert("groupId", folder->appId());
211+
valueMap.insert("appItems", fromListOfStringList(folder->pages()));
150212
list << valueMap;
151213
}
152214

0 commit comments

Comments
 (0)