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
1112namespace 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
3039QVariant 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
115172void 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