1 /**************************************************************************
2 ** This file is part of LiteIDE
3 **
4 ** Copyright (c) 2011-2017 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: bookmarkmodel.cpp
22 // Creator: visualfc <visualfc@gmail.com>
23
24 #include "bookmarkmodel.h"
25 #include <QPainter>
26 //lite_memory_check_begin
27 #if defined(WIN32) && defined(_MSC_VER) && defined(_DEBUG)
28 #define _CRTDBG_MAP_ALLOC
29 #include <stdlib.h>
30 #include <crtdbg.h>
31 #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
32 #define new DEBUG_NEW
33 #endif
34 //lite_memory_check_end
35
addNode(LiteApi::IEditorMark * mark,LiteApi::IEditorMarkNode * node)36 void BookmarkModel::addNode(LiteApi::IEditorMark *mark, LiteApi::IEditorMarkNode *node)
37 {
38 beginInsertRows(QModelIndex(), m_nodeList.size(), m_nodeList.size());
39
40 BookmarkNode *bn = createBookmarkNode(mark,node);
41 m_nodeList.append(bn);
42 m_nodeMap.insert(node,bn);
43
44 endInsertRows();
45 //selectionModel()->setCurrentIndex(index(m_bookmarksList.size()-1 , 0, QModelIndex()), QItemSelectionModel::Select | QItemSelectionModel::Clear);
46 }
47
removeNode(LiteApi::IEditorMark * mark,LiteApi::IEditorMarkNode * node)48 void BookmarkModel::removeNode(LiteApi::IEditorMark *mark, LiteApi::IEditorMarkNode *node)
49 {
50 BookmarkNode *bn = findBookmarkNode(mark,node);
51 if (!bn) {
52 return;
53 }
54 int idx = m_nodeList.indexOf(bn);
55 beginRemoveRows(QModelIndex(), idx, idx);
56
57 m_nodeMap.remove(node);
58
59 delete bn;
60
61 m_nodeList.removeAt(idx);
62 endRemoveRows();
63 // if (selectionModel()->currentIndex().isValid())
64 // selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), QItemSelectionModel::Select | QItemSelectionModel::Clear);
65 }
66
updateNode(LiteApi::IEditorMark * mark,LiteApi::IEditorMarkNode * node)67 void BookmarkModel::updateNode(LiteApi::IEditorMark *mark, LiteApi::IEditorMarkNode *node)
68 {
69 BookmarkNode *bn = findBookmarkNode(mark,node);
70 if (!bn) {
71 return;
72 }
73 bn->setLineNumber(node->blockNumber()+1);
74 bn->setLineText(node->block().text());
75 int idx = m_nodeList.indexOf(bn);
76 QModelIndex i = index(idx,0,QModelIndex());
77 emit dataChanged(i,i);
78 }
79
createBookmarkNode(LiteApi::IEditorMark * mark,LiteApi::IEditorMarkNode * node) const80 BookmarkNode *BookmarkModel::createBookmarkNode(LiteApi::IEditorMark *mark, LiteApi::IEditorMarkNode *node) const
81 {
82 BookmarkNode *n = new BookmarkNode();
83 n->setFilePath(mark->filePath());
84 n->setLineNumber(node->blockNumber()+1);
85 n->setLineText(node->block().text());
86 return n;
87 }
88
bookmarkNodeForIndex(const QModelIndex & index) const89 BookmarkNode *BookmarkModel::bookmarkNodeForIndex(const QModelIndex &index) const
90 {
91 if (!index.isValid() || index.row() >= m_nodeList.size())
92 return 0;
93 return m_nodeList.at(index.row());
94 }
95
findBookmarkNode(LiteApi::IEditorMark *,LiteApi::IEditorMarkNode * node) const96 BookmarkNode *BookmarkModel::findBookmarkNode(LiteApi::IEditorMark */*mark*/, LiteApi::IEditorMarkNode *node) const
97 {
98 return m_nodeMap.value(node);
99 }
100
BookmarkModel(QObject * parent)101 BookmarkModel::BookmarkModel(QObject *parent)
102 : QAbstractItemModel(parent)
103 {
104 }
105
index(int row,int column,const QModelIndex & parent) const106 QModelIndex BookmarkModel::index(int row, int column, const QModelIndex &parent) const
107 {
108 if (parent.isValid())
109 return QModelIndex();
110 else
111 return createIndex(row, column);
112 }
113
parent(const QModelIndex & index) const114 QModelIndex BookmarkModel::parent(const QModelIndex &index) const
115 {
116 return QModelIndex();
117 }
118
rowCount(const QModelIndex & parent) const119 int BookmarkModel::rowCount(const QModelIndex &parent) const
120 {
121 if (parent.isValid())
122 return 0;
123
124 return m_nodeList.size();
125 }
126
columnCount(const QModelIndex & parent) const127 int BookmarkModel::columnCount(const QModelIndex &parent) const
128 {
129 if (parent.isValid())
130 return 0;
131
132 return 1;
133 }
134
data(const QModelIndex & index,int role) const135 QVariant BookmarkModel::data(const QModelIndex &index, int role) const
136 {
137 if (!index.isValid() || index.column() !=0 || index.row() < 0 || index.row() >= m_nodeList.count())
138 return QVariant();
139
140 BookmarkNode *node = m_nodeList.at(index.row());
141 if (role == BookmarkModel::FileName)
142 return node->fileName();
143 if (role == BookmarkModel::LineNumber)
144 return node->lineNumber();
145 if (role == BookmarkModel::FilePath)
146 return node->filePath();
147 if (role == BookmarkModel::LineText)
148 return node->lineText();
149 if (role == BookmarkModel::Note)
150 return node->noteText();
151 if (role == Qt::ToolTipRole)
152 return QDir::toNativeSeparators(node->filePath());
153 return QVariant();
154 }
155
BookmarkDelegate(QObject * parent)156 BookmarkDelegate::BookmarkDelegate(QObject *parent)
157 : QStyledItemDelegate(parent)
158 {
159 }
160
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const161 QSize BookmarkDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
162 {
163 QStyleOptionViewItem opt = option;
164 initStyleOption(&opt, index);
165
166 QFontMetrics fm(option.font);
167 QSize s;
168 s.setWidth(option.rect.width());
169 s.setHeight(fm.height() * 2 + 10);
170 return s;
171 }
172
generateGradientPixmap(int width,int height,const QColor & color,bool selected) const173 void BookmarkDelegate::generateGradientPixmap(int width, int height, const QColor &color, bool selected) const
174 {
175 QColor c = color;
176 c.setAlpha(0);
177
178 QPixmap pixmap(width+1, height);
179 pixmap.fill(c);
180
181 QPainter painter(&pixmap);
182 painter.setPen(Qt::NoPen);
183
184 QLinearGradient lg;
185 lg.setCoordinateMode(QGradient::ObjectBoundingMode);
186 lg.setFinalStop(1,0);
187
188 lg.setColorAt(0, c);
189 lg.setColorAt(0.4, color);
190
191 painter.setBrush(lg);
192 painter.drawRect(0, 0, width+1, height);
193
194 if (selected)
195 m_selectedPixmap = pixmap;
196 else
197 m_normalPixmap = pixmap;
198 }
199
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const200 void BookmarkDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
201 {
202 QStyleOptionViewItem opt = option;
203 initStyleOption(&opt, index);
204 painter->save();
205
206 QFontMetrics fm(opt.font);
207 static int lwidth = fm.width(QLatin1String("8888")) + 18;
208
209 QColor backgroundColor;
210 QColor textColor;
211
212 bool selected = opt.state & QStyle::State_Selected;
213
214 if (selected) {
215 painter->setBrush(opt.palette.highlight().color());
216 backgroundColor = opt.palette.highlight().color();
217 if (!m_selectedPixmap)
218 generateGradientPixmap(lwidth, fm.height()+1, backgroundColor, selected);
219 } else {
220 painter->setBrush(opt.palette.background().color());
221 backgroundColor = opt.palette.background().color();
222 if (!m_normalPixmap)
223 generateGradientPixmap(lwidth, fm.height(), backgroundColor, selected);
224 }
225 painter->setPen(Qt::NoPen);
226 painter->drawRect(opt.rect);
227
228 // Set Text Color
229 if (opt.state & QStyle::State_Selected)
230 textColor = opt.palette.highlightedText().color();
231 else
232 textColor = opt.palette.text().color();
233
234 painter->setPen(textColor);
235
236
237 // TopLeft
238 QString topLeft = index.data(BookmarkModel::FileName).toString();
239 //painter->drawText(6, 2 + opt.rect.top() + fm.ascent(), topLeft);
240
241 QString topRight = index.data(BookmarkModel::LineNumber).toString();
242 // Check whether we need to be fancy and paint some background
243 int fwidth = fm.width(topLeft);
244 if (fwidth + lwidth > opt.rect.width()) {
245 int left = opt.rect.right() - lwidth;
246 painter->drawPixmap(left, opt.rect.top(), selected ? m_selectedPixmap : m_normalPixmap);
247 }
248 // topRight
249 painter->drawText(opt.rect.right() - fm.width(topRight) - 6 , 2 + opt.rect.top() + fm.ascent(), topRight);
250
251 // Directory
252 QColor mix;
253 mix.setRgbF(0.7 * textColor.redF() + 0.3 * backgroundColor.redF(),
254 0.7 * textColor.greenF() + 0.3 * backgroundColor.greenF(),
255 0.7 * textColor.blueF() + 0.3 * backgroundColor.blueF());
256 painter->setPen(mix);
257
258 QString directory = index.data(BookmarkModel::FilePath).toString();
259 int availableSpace = opt.rect.width() - fm.width("888");
260 if (fm.width(directory) > availableSpace) {
261 // We need a shorter directory
262 availableSpace -= fm.width("...");
263
264 int pos = directory.size();
265 int idx;
266 forever {
267 idx = directory.lastIndexOf("/", pos-1);
268 if (idx == -1) {
269 // Can't happen, this means the string did fit after all?
270 break;
271 }
272 int width = fm.width(directory.mid(idx, pos-idx));
273 if (width > availableSpace) {
274 directory = "..." + directory.mid(pos);
275 break;
276 } else {
277 pos = idx;
278 availableSpace -= width;
279 }
280 }
281 }
282
283 //painter->drawText(3, opt.rect.top() + fm.ascent() + fm.height() + 6, directory);
284 painter->drawText(6, 2 + opt.rect.top() + fm.ascent(), directory);
285
286 QString lineText = index.data(BookmarkModel::Note).toString().trimmed();
287 if (lineText.isEmpty())
288 lineText = index.data(BookmarkModel::LineText).toString().trimmed();
289
290 painter->drawText(6, opt.rect.top() + fm.ascent() + fm.height() + 6, lineText);
291
292 // Separator lines
293 const QRectF innerRect = QRectF(opt.rect).adjusted(0.5, 0.5, -0.5, -0.5);
294 painter->setPen(QColor::fromRgb(150,150,150));
295 painter->drawLine(innerRect.bottomLeft(), innerRect.bottomRight());
296 painter->restore();
297 }
298