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 &current, 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