1 /**************************************************************************
2 ** This file is part of LiteIDE
3 **
4 ** Copyright (c) 2011-2019 LiteIDE. All rights reserved.
5 **
6 ** This library is free software; you can redistribute it and/or
7 ** modify it under the terms of the GNU Lesser General Public
8 ** License as published by the Free Software Foundation; either
9 ** version 2.1 of the License, or (at your option) any later version.
10 **
11 ** This library is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** Lesser General Public License for more details.
15 **
16 ** In addition, as a special exception, that plugins developed for LiteIDE,
17 ** are allowed to remain closed sourced and can be distributed under any license .
18 ** These rights are included in the file LGPL_EXCEPTION.txt in this package.
19 **
20 **************************************************************************/
21 // Module: symboltreeview.cpp
22 // Creator: visualfc <visualfc@gmail.com>
23
24 #include "symboltreeview.h"
25 #include <QHeaderView>
26 #include <QFocusEvent>
27 #include <QScrollBar>
28 #include <QAbstractItemModel>
29 //lite_memory_check_begin
30 #if defined(WIN32) && defined(_MSC_VER) && defined(_DEBUG)
31 #define _CRTDBG_MAP_ALLOC
32 #include <stdlib.h>
33 #include <crtdbg.h>
34 #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
35 #define new DEBUG_NEW
36 #endif
37 //lite_memory_check_end
38
39
stringListFromIndex(const QModelIndex & index)40 static QStringList stringListFromIndex(const QModelIndex &index)
41 {
42 QStringList list;
43 if (!index.isValid())
44 return list;
45 list.append(stringListFromIndex(index.parent()));
46 list.append(index.data().toString());
47 return list;
48 }
49
indexFromStringList(QAbstractItemModel * model,QStringList & list,const QModelIndex & parent=QModelIndex ())50 static QModelIndex indexFromStringList(QAbstractItemModel *model, QStringList &list, const QModelIndex & parent = QModelIndex())
51 {
52 if (list.isEmpty())
53 return QModelIndex();
54 QString text = list.front();
55 for (int i = 0; i < model->rowCount(parent); i++) {
56 QModelIndex child = model->index(i,0,parent);
57 if (child.data().toString() == text) {
58 list.pop_front();
59 if (list.isEmpty()) {
60 return child;
61 } else {
62 QModelIndex next = indexFromStringList(model,list,child);
63 if (next.isValid())
64 return next;
65 else
66 return child;
67 }
68 }
69 }
70 return QModelIndex();
71 }
72
SymbolTreeView(QWidget * parent)73 SymbolTreeView::SymbolTreeView(QWidget *parent)
74 : QTreeView(parent)
75 {
76 init(true);
77 }
78
79
SymbolTreeView(bool bResizeToContents,QWidget * parent)80 SymbolTreeView::SymbolTreeView(bool bResizeToContents, QWidget *parent)
81 : QTreeView(parent)
82 {
83 init(bResizeToContents);
84 }
85
init(bool bResizeToContents)86 void SymbolTreeView::init(bool bResizeToContents)
87 {
88 m_bClickedItem = false;
89 m_hsbPos = 0;
90 setEditTriggers(QAbstractItemView::NoEditTriggers);
91 // setFrameStyle(QFrame::NoFrame);
92 setIndentation(indentation() * 9/10);
93 {
94 this->setHeaderHidden(true);
95 if (bResizeToContents) {
96 #if QT_VERSION >= 0x050000
97 this->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
98 #else
99 this->header()->setResizeMode(QHeaderView::ResizeToContents);
100 #endif
101 this->header()->setStretchLastSection(false);
102 }
103 this->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
104 }
105 setContextMenuPolicy(Qt::CustomContextMenu);
106 setUniformRowHeights(true);
107 setTextElideMode(Qt::ElideNone);
108 // setExpandsOnDoubleClick(false);
109 setAttribute(Qt::WA_MacShowFocusRect, false);
110 connect(this,SIGNAL(clicked(QModelIndex)),this,SLOT(clickedItem(QModelIndex)));
111 connect(this->horizontalScrollBar(),SIGNAL(valueChanged(int)),this,SLOT(hsbValueChanged(int)));
112 }
113
focusInEvent(QFocusEvent * event)114 void SymbolTreeView::focusInEvent(QFocusEvent *event)
115 {
116 if (event->reason() != Qt::PopupFocusReason)
117 QTreeView::focusInEvent(event);
118 }
119
focusOutEvent(QFocusEvent * event)120 void SymbolTreeView::focusOutEvent(QFocusEvent *event)
121 {
122 if (event->reason() != Qt::PopupFocusReason)
123 QTreeView::focusOutEvent(event);
124 }
125
topViewIndex()126 QModelIndex SymbolTreeView::topViewIndex()
127 {
128 return indexAt(QPoint(1,1));
129 }
130
reset()131 void SymbolTreeView::reset()
132 {
133 QTreeView::reset();
134 //setRootIndex(model()->index(0,0));
135 //this->setRootIndex(QModelIndex());
136 }
137
getTreeExpands(const QModelIndex & parent,QList<QModelIndex> & list) const138 void SymbolTreeView::getTreeExpands(const QModelIndex &parent, QList<QModelIndex> &list) const
139 {
140 for (int i = 0; i < this->model()->rowCount(parent); i++) {
141 QModelIndex index = this->model()->index(i,0,parent);
142 if (this->isExpanded(index)) {
143 list.append(index);
144 getTreeExpands(index,list);
145 }
146 }
147 }
148
clickedItem(QModelIndex)149 void SymbolTreeView::clickedItem(QModelIndex)
150 {
151 this->m_bClickedItem = true;
152 this->m_hsbPos = this->horizontalScrollBar()->sliderPosition();
153 }
154
hsbValueChanged(int)155 void SymbolTreeView::hsbValueChanged(int)
156 {
157 if (this->m_bClickedItem) {
158 this->m_bClickedItem = false;
159 this->horizontalScrollBar()->setValue(this->m_hsbPos);
160 }
161 }
162
expandIndexs() const163 QList<QModelIndex> SymbolTreeView::expandIndexs() const
164 {
165 QList<QModelIndex> expands;
166 getTreeExpands(QModelIndex(),expands);
167 return expands;
168 }
169
currentChanged(const QModelIndex & current,const QModelIndex & previous)170 void SymbolTreeView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
171 {
172 QTreeView::currentChanged(current,previous);
173 emit currentIndexChanged(current, previous);
174 }
175
saveState(SymbolTreeState * state)176 void SymbolTreeView::saveState(SymbolTreeState *state)
177 {
178 if (!state) {
179 return;
180 }
181 state->expands.clear();
182
183 foreach (QModelIndex index, this->expandIndexs()) {
184 state->expands.append(stringListFromIndex(index));
185 }
186
187 state->cur = stringListFromIndex(this->currentIndex());
188 state->vbar = verticalScrollBar()->value();
189 state->hbar = horizontalScrollBar()->value();
190 }
191
loadState(QAbstractItemModel * model,SymbolTreeState * state)192 void SymbolTreeView::loadState(QAbstractItemModel *model,SymbolTreeState *state)
193 {
194 //load state
195 //this->expandToDepth(0)
196 QListIterator<QStringList> ie(state->expands);
197 while (ie.hasNext()) {
198 QStringList expandPath = ie.next();
199 QModelIndex expandIndex = indexFromStringList(model,expandPath);
200 if (expandIndex.isValid()) {
201 this->setExpanded(expandIndex,true);
202 }
203 }
204
205 QModelIndex curIndex = indexFromStringList(model,state->cur);
206 if (curIndex.isValid()) {
207 this->setCurrentIndex(curIndex);
208 }
209 if (state->vbar != -1) {
210 verticalScrollBar()->setValue(state->vbar);
211 }
212 if (state->hbar != -1) {
213 horizontalScrollBar()->setValue(state->hbar);
214 }
215 }
216
keyPressEvent(QKeyEvent * event)217 void SymbolTreeView::keyPressEvent(QKeyEvent *event)
218 {
219 // Note: This always eats the event
220 // whereas QAbstractItemView never eats it
221 if ((event->key() == Qt::Key_Return
222 || event->key() == Qt::Key_Enter)
223 && event->modifiers() == 0
224 && QTreeView::currentIndex().isValid()
225 && QTreeView::state() != QAbstractItemView::EditingState) {
226 emit QTreeView::activated(QTreeView::currentIndex());
227 emit enterKeyPressed(QTreeView::currentIndex());
228 return;
229 }
230 QTreeView::keyPressEvent(event);
231 }
232