1
2
3 #include "toonzqt/gutil.h"
4 #include "toonzqt/treemodel.h"
5
6 #include <QStringList>
7 #include <QTreeView>
8 #include <QHeaderView>
9 #include <QMouseEvent>
10 #include <qvariant.h>
11 #include <qicon.h>
12 #include <qtextedit.h>
13
14 #include "tfx.h"
15 #include <assert.h>
16
17 //====================================================================================================
18 // Item
19 //----------------------------------------------------------------------------------------------------
20
Item()21 TreeModel::Item::Item()
22 : m_model(0), m_parent(0), m_depth(0), m_row(0), m_opened(false) {}
23
24 //------------------------------------------------------------------------------------------------------------------
25
~Item()26 TreeModel::Item::~Item() {
27 qDeleteAll(m_childItems);
28 m_childItems.clear();
29 m_model = 0;
30 m_row = 0;
31 m_depth = 0;
32 m_parent = 0;
33 }
34
35 //------------------------------------------------------------------------------------------------------------------
36
updateChild(Item * child,int row)37 void TreeModel::Item::updateChild(Item *child, int row) {
38 assert(m_model);
39 child->m_model = m_model;
40 child->m_depth = m_depth + 1;
41 child->m_parent = this;
42 child->m_row = row;
43 }
44
45 //------------------------------------------------------------------------------------------------------------------
46
updateChildren()47 void TreeModel::Item::updateChildren() {
48 int i;
49 for (i = 0; i < m_childItems.size(); i++) updateChild(m_childItems[i], i);
50 }
51
52 //------------------------------------------------------------------------------------------------------------------
53
appendChild(TreeModel::Item * child)54 TreeModel::Item *TreeModel::Item::appendChild(TreeModel::Item *child) {
55 assert(child);
56 assert(!m_childItems.contains(child));
57 updateChild(child, m_childItems.size());
58 m_childItems.append(child);
59 return child;
60 }
61
62 //------------------------------------------------------------------------------------------------------------------
63 /*
64 void TreeModel::Item::deleteChild(Item *child)
65 {
66 int index = m_childItems.indexOf(child);
67 if(index != -1)
68 {
69 m_childItems.takeAt(index);
70 assert(!m_childItems.contains(child));
71 // m_childItems is not supposed to contain duplicated entries
72 delete child;
73 updateChildren();
74 }
75 }
76 */
77
78 //------------------------------------------------------------------------------------------------------------------
79 /*
80 Item* matchItem(Item*item, QList<Item*> &items)
81 {
82 void *itemData = item->getInternalPointer();
83 if(!itemData) return 0;
84 int i;
85 for(i=0;i<items.size();i++)
86 if(items.at(i)->getInternalPointer()==itemData)
87 return items.at(i);
88 return 0;
89 }
90 */
91 //------------------------------------------------------------------------------------------------------------------
92
setChildren(QList<Item * > & newChildren)93 void TreeModel::Item::setChildren(QList<Item *> &newChildren) {
94 assert(m_model);
95 QModelIndex itemIndex = createIndex();
96
97 // save old children and clear 'm_childItems'
98 QList<Item *> oldChildren(m_childItems);
99 m_childItems.clear();
100 int i;
101
102 // for each child to add
103 for (i = 0; i < newChildren.size(); i++) {
104 Item *newChild = newChildren.at(i);
105 void *newInternalPointer = newChild->getInternalPointer();
106 if (newInternalPointer != 0) {
107 // search among old children
108 int j;
109 for (j = 0; j < oldChildren.size(); j++)
110 if (oldChildren.at(j)->getInternalPointer() == newInternalPointer)
111 break;
112 if (j < oldChildren.size()) {
113 Item *oldChild = oldChildren.takeAt(j);
114 if (oldChild != newChild) {
115 // Found! Delete newChild, remove it from 'newChildren' and
116 // update consequently the index
117 delete newChild;
118 newChildren.takeAt(i);
119 i--;
120 // use the found child instead of the new one.
121 newChild = oldChild;
122 oldChild->refresh();
123 } else {
124 // should never happen; (if it happens this is not a big problem)
125 assert(0);
126 }
127 }
128 }
129 // add the new child to 'm_childItems'
130 m_childItems.push_back(newChild);
131 }
132 // update children model, row, parent, etc.
133 updateChildren();
134
135 // postpone item deletion to avoid the (possible) reuse of the
136 // same pointer for the newly created items. (Pointers match is
137 // used updating persistent indices. see: TreeModel::endRefresh())
138 for (i = 0; i < oldChildren.size(); i++) {
139 Item *itemToDelete = oldChildren[i];
140 if (!m_model->m_itemsToDelete.contains(itemToDelete))
141 m_model->m_itemsToDelete.push_back(itemToDelete);
142 }
143 }
144
145 //------------------------------------------------------------------------------------------------------------------
146
data(int role) const147 QVariant TreeModel::Item::data(int role) const {
148 if (role == Qt::DecorationRole)
149 return createQIcon("folder", true);
150 else
151 return QVariant();
152 }
153
154 //------------------------------------------------------------------------------------------------------------------
155
createIndex()156 QModelIndex TreeModel::Item::createIndex() {
157 return m_parent ? m_model->createIndex(m_row, 0, this) : QModelIndex();
158 }
159
160 //====================================================================================================
161 // TreeModel
162 //----------------------------------------------------------------------------------------------------
163
TreeModel(TreeView * parent)164 TreeModel::TreeModel(TreeView *parent)
165 : QAbstractItemModel(parent), m_rootItem(0), m_view(parent) {}
166
167 //------------------------------------------------------------------------------------------------------------------
168
~TreeModel()169 TreeModel::~TreeModel() { delete m_rootItem; }
170
171 //------------------------------------------------------------------------------------------------------------------
172
setExpandedItem(const QModelIndex & index,bool expanded)173 void TreeModel::setExpandedItem(const QModelIndex &index, bool expanded) {
174 if (m_view) m_view->setExpanded(index, expanded);
175 }
176
177 //------------------------------------------------------------------------------------------------------------------
178
beginRefresh()179 void TreeModel::beginRefresh() { emit layoutAboutToBeChanged(); }
180
181 //------------------------------------------------------------------------------------------------------------------
182
endRefresh()183 void TreeModel::endRefresh() {
184 QList<QModelIndex> oldIndices, newIndices;
185 int i;
186 QList<Item *>::iterator it;
187
188 // comment out as no subclass of TreeModel reimplement removeRows() for now
189 // and it causes assertion failure on calling beginRemoveRows() when deleting
190 // the last column in the xsheet
191 /*
192 for (i = m_itemsToDelete.size() - 1; i >= 0; i--) {
193 int row = m_itemsToDelete[i]->getRow();
194 Item *parentItem = m_itemsToDelete[i]->getParent();
195 QModelIndex parentIndex =
196 parentItem ? parentItem->createIndex() : QModelIndex();
197
198 beginRemoveRows(parentIndex, row, row);
199 removeRows(row, 1, parentIndex); // NOTE: This is currently doing NOTHING?
200 (see
201 // Qt's manual)
202 endRemoveRows();
203 }*/
204
205 qDeleteAll(m_itemsToDelete);
206 m_itemsToDelete.clear();
207
208 if (!persistentIndexList().empty()) {
209 for (i = 0; i < persistentIndexList().size(); i++) {
210 QModelIndex oldIndex = persistentIndexList()[i];
211 Item *item = static_cast<Item *>(oldIndex.internalPointer());
212 if (item) {
213 QModelIndex newIndex = item->createIndex();
214 if (oldIndex != newIndex) {
215 oldIndices.push_back(oldIndex);
216 newIndices.push_back(newIndex);
217 }
218 }
219 }
220 changePersistentIndexList(oldIndices, newIndices);
221 }
222
223 emit layoutChanged();
224 }
225
226 //------------------------------------------------------------------------------------------------------------------
227
columnCount(const QModelIndex & parent) const228 int TreeModel::columnCount(const QModelIndex &parent) const { return 1; }
229
230 //------------------------------------------------------------------------------------------------------------------
231
flags(const QModelIndex & index) const232 Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const {
233 if (!index.isValid()) return 0;
234 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
235 }
236
237 //------------------------------------------------------------------------------------------------------------------
238
index(int row,int column,const QModelIndex & parent) const239 QModelIndex TreeModel::index(int row, int column,
240 const QModelIndex &parent) const {
241 // column=!0 are not supported
242 if (column != 0) return QModelIndex();
243
244 Item *parentItem =
245 parent.isValid() ? (Item *)(parent.internalPointer()) : m_rootItem;
246 // if m_rootItem has not been defined yet. (It should not happen, but just in
247 // case)
248 if (!parentItem) return QModelIndex();
249
250 int childCount = parentItem->getChildCount();
251 if (row < 0 || row >= childCount) return QModelIndex();
252
253 Item *item = parentItem->getChild(row);
254 if (!item) return QModelIndex(); // it should never happen
255 return item->createIndex();
256 }
257
258 //------------------------------------------------------------------------------------------------------------------
259
parent(const QModelIndex & index) const260 QModelIndex TreeModel::parent(const QModelIndex &index) const {
261 if (!index.isValid()) return QModelIndex();
262
263 Item *item = (Item *)index.internalPointer();
264
265 TreeModel::Item *parentItem = item->getParent();
266
267 if (!parentItem || parentItem == m_rootItem) return QModelIndex();
268
269 return parentItem->createIndex();
270 }
271
272 //------------------------------------------------------------------------------------------------------------------
273
rowCount(const QModelIndex & parent) const274 int TreeModel::rowCount(const QModelIndex &parent) const {
275 if (parent.column() > 0) return 0;
276
277 if (!parent.isValid())
278 return m_rootItem ? m_rootItem->getChildCount() : 0;
279 else
280 return ((Item *)(parent.internalPointer()))->getChildCount();
281 }
282
283 //------------------------------------------------------------------------------------------------------------------
284
onExpanded(const QModelIndex & index)285 void TreeModel::onExpanded(const QModelIndex &index) {
286 if (!index.isValid()) return;
287
288 Item *item = (Item *)(index.internalPointer());
289 item->setIsOpen(true);
290 }
291
292 //---------------------------------------------------------------------------------------------------------------
293
onCollapsed(const QModelIndex & index)294 void TreeModel::onCollapsed(const QModelIndex &index) {
295 if (!index.isValid()) return;
296
297 Item *item = (Item *)(index.internalPointer());
298 item->setIsOpen(false);
299 }
300
301 //---------------------------------------------------------------------------------------------------------------
302
data(const QModelIndex & index,int role) const303 QVariant TreeModel::data(const QModelIndex &index, int role) const {
304 if (!index.isValid()) return QVariant();
305 Item *item = static_cast<Item *>(index.internalPointer());
306 return item->data(role);
307 }
308
309 //---------------------------------------------------------------------------------------------------------------
310
setRootItem(Item * rootItem)311 void TreeModel::setRootItem(Item *rootItem) {
312 if (rootItem == m_rootItem) return;
313 delete m_rootItem;
314 m_rootItem = rootItem;
315 if (m_rootItem) m_rootItem->setModel(this);
316 }
317
318 // postpone freeing, so existing items can be referenced while refreshing.
setRootItem_NoFree(Item * rootItem)319 void TreeModel::setRootItem_NoFree(Item *rootItem) {
320 if (rootItem == m_rootItem) return;
321 m_rootItem = rootItem;
322 if (m_rootItem) m_rootItem->setModel(this);
323 }
324
325 //---------------------------------------------------------------------------------------------------------------
326
setRowHidden(int row,const QModelIndex & parent,bool hide)327 void TreeModel::setRowHidden(int row, const QModelIndex &parent, bool hide) {
328 if (m_view) m_view->setRowHidden(row, parent, hide);
329 }
330
331 //====================================================================================================
332 // TreeView
333 //----------------------------------------------------------------------------------------------------
334
TreeView(QWidget * parent)335 TreeView::TreeView(QWidget *parent) : QTreeView(parent), m_dragging(false) {
336 header()->hide();
337 setUniformRowHeights(true);
338 setIconSize(QSize(32, 32));
339 }
340
341 //-----------------------------------------------------------------------------
342
343 //! Resizes viewport to contents
resizeToConts(void)344 void TreeView::resizeToConts(void) { resizeColumnToContents(0); }
345
346 //-----------------------------------------------------------------------------
347
resizeEvent(QResizeEvent * event)348 void TreeView::resizeEvent(QResizeEvent *event) {
349 resizeColumnToContents(0);
350 QTreeView::resizeEvent(event);
351 }
352
353 //----------------------------------------------------------------------------------------------------------------
354
setModel(TreeModel * model)355 void TreeView::setModel(TreeModel *model) {
356 QTreeView::setModel(model);
357 disconnect();
358
359 connect(this, SIGNAL(expanded(const QModelIndex &)), model,
360 SLOT(onExpanded(const QModelIndex &)));
361 connect(this, SIGNAL(collapsed(const QModelIndex &)), model,
362 SLOT(onCollapsed(const QModelIndex &)));
363 // setItemDelegate(new Delegate(this));
364
365 // Connect all possible changes that can alter the
366 // bottom horizontal scrollbar to resize contents...
367 connect(this, SIGNAL(expanded(const QModelIndex &)), this,
368 SLOT(resizeToConts()));
369
370 connect(this, SIGNAL(collapsed(const QModelIndex &)), this,
371 SLOT(resizeToConts()));
372
373 connect(this->model(), SIGNAL(layoutChanged()), this, SLOT(resizeToConts()));
374 }
375
376 //----------------------------------------------------------------------------------------------------------------
377
mouseDoubleClickEvent(QMouseEvent *)378 void TreeView::mouseDoubleClickEvent(QMouseEvent *) {
379 // ignore double click!
380 }
381
mousePressEvent(QMouseEvent * e)382 void TreeView::mousePressEvent(QMouseEvent *e) {
383 if (e->button() != Qt::RightButton) QTreeView::mousePressEvent(e);
384 QModelIndex index = indexAt(e->pos());
385 if (index.isValid()) {
386 TreeModel::Item *item =
387 static_cast<TreeModel::Item *>(index.internalPointer());
388 QRect itemRect = visualRect(index);
389 QPoint itemPos = e->pos() - itemRect.topLeft();
390 if (e->button() == Qt::RightButton) {
391 if (selectionMode() != QAbstractItemView::ExtendedSelection)
392 setCurrentIndex(item->createIndex());
393 onClick(item, itemPos, e);
394 openContextMenu(item, e->globalPos());
395 } else if (e->button() == Qt::LeftButton) {
396 m_dragging = true;
397 setMouseTracking(true);
398 onClick(item, itemPos, e);
399 }
400 // for drag & drop
401 else if (e->button() == Qt::MidButton) {
402 m_dragging = true;
403 setMouseTracking(true);
404 onMidClick(item, itemPos, e);
405 }
406 }
407 }
408
409 //----------------------------------------------------------------------------------------------------------------
410
mouseMoveEvent(QMouseEvent * e)411 void TreeView::mouseMoveEvent(QMouseEvent *e) {
412 QTreeView::mouseMoveEvent(e);
413 if (m_dragging) {
414 QModelIndex index = indexAt(e->pos());
415 if (index.isValid()) {
416 TreeModel::Item *item =
417 static_cast<TreeModel::Item *>(index.internalPointer());
418 QRect itemRect = visualRect(index);
419 QPoint itemPos = e->pos() - itemRect.topLeft();
420 onDrag(item, itemPos, e);
421 }
422 }
423 }
424
425 //----------------------------------------------------------------------------------------------------------------
426
mouseReleaseEvent(QMouseEvent * e)427 void TreeView::mouseReleaseEvent(QMouseEvent *e) {
428 QTreeView::mouseReleaseEvent(e);
429 if (m_dragging) {
430 m_dragging = false;
431 setMouseTracking(false);
432 onRelease();
433 }
434 }
435
436 //----------------------------------------------------------------------------------------------------------------
437
438 /*
439 bool TreeView::Delegate::editorEvent(QEvent *e, QAbstractItemModel
440 *abstractModel, const QStyleOptionViewItem &option, const QModelIndex &index)
441 {
442 if(e->type() != QEvent::MouseButtonPress) return false;
443 TreeModel *model = dynamic_cast<TreeModel *>(abstractModel);
444 if(!model || !index.isValid()) return false;
445
446 TreeModel::Item *item = static_cast<TreeModel::Item
447 *>(index.internalPointer());
448 QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(e);
449 QPoint pos = mouseEvent->pos();
450
451 m_treeView->onClick(item, pos, option);
452 return true;
453 }
454 */
455