Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions applets/dde-apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ add_library(dde-apps SHARED ${DBUS_INTERFACES}
appslaunchtimes.h
categoryutils.cpp
categoryutils.h
itemspage.cpp
itemspage.h
)

target_link_libraries(dde-apps PRIVATE
Expand Down
1 change: 0 additions & 1 deletion applets/dde-apps/amappitemmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

#include <DUtil>
#include <QtConcurrent>
#include <tuple>

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

Expand Down
50 changes: 27 additions & 23 deletions applets/dde-apps/appgroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "appgroup.h"
#include "appgroupmanager.h"
#include "appitemmodel.h"
#include "itemspage.h"

#include <QLoggingCategory>
#include <algorithm>
Expand All @@ -14,44 +15,47 @@ Q_LOGGING_CATEGORY(appGroupLog, "org.deepin.ds.dde-apps.appgroup")
namespace apps {
AppGroup::AppGroup(const QString &groupId, const QString &name, const QList<QStringList> &appIDs)
: AppItem(groupId, AppItemModel::FolderItemType)
, m_itemsPage(new ItemsPage(name, groupId == QStringLiteral("internal/folder/0") ? (4 * 8) : (3 * 4)))
{
if (groupId == QStringLiteral("internal/folder/0")) {
setItemsPerPage(4 * 8);
} else {
setItemsPerPage(3 * 4);
setItemsPerPage(m_itemsPage->maxItemCountPerPage());
setAppName(m_itemsPage->name());
// folder id is a part of its groupId: "internal/folder/{folderId}"
setFolderId(groupId.section('/', -1).toInt());

for (const QStringList &items : appIDs) {
m_itemsPage->appendPage(items);
}
setAppName(name);
setAppItems(appIDs);
}

QList<QStringList> AppGroup::appItems() const
AppGroup::~AppGroup()
{
QList<QStringList> res;
auto pages = data(AppGroupManager::GroupAppItemsRole).toList();
std::transform(pages.begin(), pages.end(), std::back_inserter(res), [](const QVariant &data) {
return data.toStringList();
});
delete m_itemsPage;
}

return res;
int AppGroup::folderId() const
{
return data(AppGroupManager::GroupIdRole).toInt();
}

void AppGroup::setAppItems(const QList<QStringList> &items)
QList<QStringList> AppGroup::pages() const
{
QVariantList data;
std::transform(items.begin(), items.end(), std::back_inserter(data), [](const QStringList &c) {
QVariantList tmp;
std::transform(c.begin(), c.end(), std::back_inserter(tmp), [](const QString &s) {
return s;
});
return tmp;
});
return setData(data, AppGroupManager::GroupAppItemsRole);
return m_itemsPage->allPagedItems();
}

ItemsPage *AppGroup::itemsPage()
{
return m_itemsPage;
}

void AppGroup::setItemsPerPage(int number)
{
return setData(number, AppGroupManager::GroupItemsPerPageRole);
}

void AppGroup::setFolderId(int folderId)
{
setData(folderId, AppGroupManager::GroupIdRole);
}

}

14 changes: 9 additions & 5 deletions applets/dde-apps/appgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@

#include "appitem.h"

class ItemsPage;
namespace apps {
class AppGroup : public AppItem
{
public:
explicit AppGroup(const QString &groupId, const QString &name, const QList<QStringList> &appItemIDs);
~AppGroup() override;

QString name() const;
void setName(const QString &name);

QList<QStringList> appItems() const;
void setAppItems(const QList<QStringList> &items);
int folderId() const;
QList<QStringList> pages() const;
ItemsPage * itemsPage();

private:
void setItemsPerPage(int number);
void setFolderId(int folderId);

ItemsPage * m_itemsPage;
};
}
190 changes: 126 additions & 64 deletions applets/dde-apps/appgroupmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

#include "appgroupmanager.h"
#include "appgroup.h"
#include "itemspage.h"
#include "amappitemmodel.h"

#include <QtConcurrent>
#define TOPLEVEL_FOLDERID 0

namespace apps {

Expand All @@ -21,10 +22,18 @@

loadAppGroupInfo();

connect(m_referenceModel, &AMAppItemModel::rowsInserted, this, [this](){
onReferenceModelChanged();
saveAppGroupInfo();
});
connect(m_referenceModel, &AMAppItemModel::rowsRemoved, this, [this](){
onReferenceModelChanged();
saveAppGroupInfo();
});
connect(m_dumpTimer, &QTimer::timeout, this, [this](){
dumpAppGroupInfo();
saveAppGroupInfo();
});
connect(this, &AppGroupManager::dataChanged, this, &AppGroupManager::dumpAppGroupInfo);
connect(this, &AppGroupManager::dataChanged, this, &AppGroupManager::saveAppGroupInfo);
}

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

std::tuple<int, int, int> AppGroupManager::getAppGroupInfo(const QString &appId)
// Find the item's location. If folderId is -1, search all folders.
std::tuple<int, int, int> AppGroupManager::findItem(const QString &appId, int folderId)
{
std::tuple<int, int, int> res = {-1, -1, -1};
do {
int groupPos, pagePos;
std::tie(groupPos, pagePos) = m_map.value(appId, std::make_tuple<int, int>(-1, -1));
auto groupIndex = index(groupPos, 0);

if (!groupIndex.isValid())
break;
int page, idx;

auto pages = groupIndex.data(GroupAppItemsRole).toList();
if (pages.length() == 0)
break;

auto items = pages.value(pagePos).toStringList();
if (items.length() == 0)
break;

auto itemPos = items.indexOf(appId);
res = std::make_tuple(groupPos, pagePos, itemPos);
} while (0);
for (int i = 0; i < rowCount(); i++) {
auto group = static_cast<AppGroup*>(itemFromIndex(index(i, 0)));
if (folderId >= 0 && group->folderId() != folderId) {
continue;
}
std::tie(page, idx) = group->itemsPage()->findItem(appId);
if (page != -1) {
return std::make_tuple(group->folderId(), page, idx);
}
}

return res;
return std::make_tuple(-1, -1, -1);
}

void AppGroupManager::setAppGroupInfo(const QString &appId, std::tuple<int, int, int> groupInfo)
void AppGroupManager::appendItemToGroup(const QString &appId, int groupId)
{
int groupPos, pagePos, itemPos;
std::tie(groupPos, pagePos, itemPos) = groupInfo;

auto groupIndex = index(groupPos, 0);
if (!groupIndex.isValid()) {
return;
}

auto appItems = groupIndex.data(GroupAppItemsRole).value<QList<QStringList>>();
int groupItemsPerPage = groupIndex.data(GroupItemsPerPageRole).toInt();

for (int i = pagePos; i < appItems.length() - 1; i++) {
appItems[i].insert(itemPos, appId);
m_map.insert(appId, std::make_tuple(groupPos, pagePos));
auto folder = group(groupId);
Q_CHECK_PTR(folder);
folder->itemsPage()->appendItem(appId);
}

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

appItems[i + 1].insert(0, item);
m_map.insert(item, std::make_tuple(groupPos, i + 1));
QModelIndex AppGroupManager::groupIndexById(int groupId)
{
for (int i = 0; i < rowCount(); i++) {
auto groupIndex = index(i, 0);
auto data = groupIndex.data(GroupIdRole);
if (data.toInt() == groupId) {
return groupIndex;
}
}
return QModelIndex();
}

if (appItems.length() > 1 && appItems.last().length() > groupItemsPerPage) {
auto item = appItems.last().takeLast();
appItems.append({item});
AppGroup * AppGroupManager::group(int groupId)
{
auto groupIndex = groupIndexById(groupId);
if (!groupIndex.isValid()) {
return nullptr;
}
auto group = static_cast<AppGroup*>(itemFromIndex(groupIndex));
return group;
}

if (pagePos > appItems.length()) {
appItems.append({appId});
AppGroup * AppGroupManager::group(QModelIndex idx)
{
if (!idx.isValid()) {
return nullptr;
}
auto group = static_cast<AppGroup*>(itemFromIndex(idx));
return group;
}

QVariantList AppGroupManager::fromListOfStringList(const QList<QStringList> & list)
{
QVariantList data;
std::transform(appItems.begin(), appItems.end(), std::back_inserter(data), [](const QStringList &items) {
std::transform(list.begin(), list.end(), std::back_inserter(data), [](const QStringList &items) {
QVariantList tmp;
std::transform(items.begin(), items.end(), std::back_inserter(tmp), [](const auto &item) {
return QVariant::fromValue(item);
});
return tmp;
return items;
});

setData(groupIndex, data);
return data;
}

// On AM model changed, add newly installed apps to group (if any) and remove apps that are no longer exists.
void AppGroupManager::onReferenceModelChanged()
{
// Avoid remove all existing records when first time (AM model is not ready).
if (m_referenceModel->rowCount() == 0) {
qDebug() << "referenceModel not ready, wait for next time";
return;
}

QSet<QString> appSet;
for (int i = 0; i < m_referenceModel->rowCount(); i++) {
const auto modelIndex = m_referenceModel->index(i, 0);
const bool noDisplay = m_referenceModel->data(modelIndex, AppItemModel::NoDisplayRole).toBool();
if (noDisplay) {
continue;
}
const QString & desktopId = m_referenceModel->data(m_referenceModel->index(i, 0), AppItemModel::DesktopIdRole).toString();
appSet.insert(desktopId);
// add all existing ones if they are not already in
int folder, page, idx;

Check warning on line 148 in applets/dde-apps/appgroupmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Unused variable: page

Check warning on line 148 in applets/dde-apps/appgroupmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Unused variable: idx
std::tie(folder, std::ignore, std::ignore) = findItem(desktopId);
if (folder == -1) {
appendItemToGroup(desktopId, TOPLEVEL_FOLDERID);
}
}

// remove all non-existing ones
for (int i = rowCount() - 1; i >= 0; i--) {
auto folder = group(index(i, 0));
Q_CHECK_PTR(folder);
folder->itemsPage()->removeItemsNotIn(appSet);
// check if group itself is also empty, remove them too.
if (folder->itemsPage()->itemCount() == 0 && folder->folderId() != TOPLEVEL_FOLDERID) {
QString groupId = folder->appId();
removeRow(i);
removeItemFromGroup(groupId, TOPLEVEL_FOLDERID);
}
}

// TODO: emit datachanged signal?
// TODO: save item arrangement to user data?
}

void AppGroupManager::loadAppGroupInfo()
{
auto groups = m_config->value("Groups").toList();

for (int i = 0; i < groups.length(); i++) {
auto group = groups[i].toMap();
auto folderId = group.value("folderId", "").toString();
auto groupId = group.value("groupId", "").toString();
auto name = group.value("name", "").toString();
auto pages = group.value("appItems", QVariantList()).toList();
QList<QStringList> items;

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

if (folderId.isEmpty()) {
folderId = assignGroupId();
if (groupId.isEmpty()) {
groupId = assignGroupId();
}
auto p = new AppGroup(folderId, name, items);
auto p = new AppGroup(groupId, name, items);
appendRow(p);
}

// always ensure top-level group exists
if (rowCount() == 0) {
auto p = new AppGroup(assignGroupId(), "Top Level", {});
Q_ASSERT(p->folderId() == TOPLEVEL_FOLDERID);
appendRow(p);
}
}

void AppGroupManager::dumpAppGroupInfo()
void AppGroupManager::saveAppGroupInfo()
{
QVariantList list;
for (int i = 0; i < rowCount(); i++) {
auto data = index(i, 0);
auto folder = group(index(i, 0));
QVariantMap valueMap;
valueMap.insert("name", data.data(AppItemModel::NameRole));
valueMap.insert("folderId", data.data(AppItemModel::DesktopIdRole));
valueMap.insert("appItems", data.data(GroupAppItemsRole));
valueMap.insert("name", folder->data(AppItemModel::NameRole));
valueMap.insert("groupId", folder->appId());
valueMap.insert("appItems", fromListOfStringList(folder->pages()));
list << valueMap;
}

Expand Down
Loading
Loading