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