Unity 8
unitymenumodelstack.cpp
1 /*
2  * Copyright 2013 Canonical Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authors:
17  * Nick Dedekind <nick.dedekind@canonical.com>
18  */
19 
20 #include "unitymenumodelstack.h"
21 
22 #include <QDebug>
23 #include <unitymenumodel.h>
24 
25 class UnityMenuModelEntry : public QObject {
26  Q_OBJECT
27 public:
28  UnityMenuModelEntry(UnityMenuModel* model, UnityMenuModel* parentModel, int index)
29  : m_model(model),
30  m_parentModel(parentModel),
31  m_index(index)
32  {
33  if (m_parentModel) {
34  QObject::connect(m_parentModel, &UnityMenuModel::rowsInserted, this, &UnityMenuModelEntry::onRowsInserted);
35  QObject::connect(m_parentModel, &UnityMenuModel::rowsRemoved, this, &UnityMenuModelEntry::onRowsRemoved);
36  QObject::connect(m_parentModel, &UnityMenuModel::modelReset, this, &UnityMenuModelEntry::onModelReset);
37  }
38  }
39 
40  UnityMenuModel* model() const { return m_model; }
41 
42 private Q_SLOTS:
43  void onRowsInserted(const QModelIndex&, int start, int end)
44  {
45  int delta = end-start + 1;
46  if (start <= m_index) {
47  m_index += delta;
48  }
49  }
50 
51  void onRowsRemoved(const QModelIndex&, int start, int end)
52  {
53  int delta = end-start + 1;
54  if (start <= m_index) {
55  if (start + delta > m_index) {
56  // in the range removed
57  Q_EMIT remove();
58  disconnect(m_parentModel, 0, this, 0);
59  } else {
60  m_index -= delta;
61  }
62  }
63  }
64 
65  void onModelReset()
66  {
67  Q_EMIT remove();
68  disconnect(m_parentModel, 0, this, 0);
69  }
70 
71 Q_SIGNALS:
72  void remove();
73 
74 private:
75  UnityMenuModel* m_model;
76  UnityMenuModel* m_parentModel;
77  int m_index;
78 };
79 
80 UnityMenuModelStack::UnityMenuModelStack(QObject* parent)
81  : QObject(parent)
82 {
83 }
84 
85 UnityMenuModelStack::~UnityMenuModelStack()
86 {
87  qDeleteAll(m_menuModels);
88  m_menuModels.clear();
89 }
90 
91 UnityMenuModel* UnityMenuModelStack::head() const
92 {
93  return !m_menuModels.isEmpty() ? m_menuModels.first()->model() : nullptr;
94 }
95 
96 void UnityMenuModelStack::setHead(UnityMenuModel* model)
97 {
98  if (head() != model) {
99  qDeleteAll(m_menuModels);
100  m_menuModels.clear();
101 
102  push(model, 0);
103  Q_EMIT headChanged(model);
104  }
105 }
106 
107 UnityMenuModel* UnityMenuModelStack::tail() const
108 {
109  return !m_menuModels.isEmpty() ? m_menuModels.last()->model() : nullptr;
110 }
111 
112 int UnityMenuModelStack::count() const
113 {
114  return m_menuModels.count();
115 }
116 
117 void UnityMenuModelStack::push(UnityMenuModel* model, int index)
118 {
119  UnityMenuModelEntry* entry = new UnityMenuModelEntry(model, tail(), index);
120  QObject::connect(entry, &UnityMenuModelEntry::remove, this, &UnityMenuModelStack::onRemove);
121 
122  m_menuModels << entry;
123  Q_EMIT tailChanged(model);
124  Q_EMIT countChanged(m_menuModels.count());
125 }
126 
127 UnityMenuModel* UnityMenuModelStack::pop()
128 {
129  if (m_menuModels.isEmpty()) {
130  return nullptr;
131  }
132  UnityMenuModelEntry* entry = m_menuModels.takeLast();
133  UnityMenuModel* model = entry->model();
134  entry->deleteLater();
135 
136  Q_EMIT tailChanged(tail());
137  if (m_menuModels.isEmpty()) {
138  Q_EMIT headChanged(nullptr);
139  }
140  Q_EMIT countChanged(m_menuModels.count());
141 
142  return model;
143 }
144 
145 void UnityMenuModelStack::onRemove()
146 {
147  UnityMenuModelEntry* removed = qobject_cast<UnityMenuModelEntry*>(sender());
148  if (!m_menuModels.contains(removed))
149  return;
150 
151  for (int i = m_menuModels.count() -1; i >= 0; i--) {
152  UnityMenuModelEntry* entry = m_menuModels[i];
153  pop();
154  if (entry == removed) {
155  break;
156  }
157  }
158 }
159 
160 #include "unitymenumodelstack.moc"