1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the documentation of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of The Qt Company Ltd nor the names of its
21 **     contributors may be used to endorse or promote products derived
22 **     from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 /*!
42     view.cpp
43 
44     Provides a view to represent a one-dimensional sequence of integers
45     obtained from a list model as a series of rows.
46 */
47 
48 #include <QAbstractItemModel>
49 #include <QBrush>
50 #include <QItemSelection>
51 #include <QPainter>
52 #include <QPaintEvent>
53 #include <QPen>
54 #include <QPoint>
55 #include <QResizeEvent>
56 #include <QScrollBar>
57 #include <QSizePolicy>
58 
59 #include "view.h"
60 
LinearView(QWidget * parent)61 LinearView::LinearView(QWidget *parent)
62     : QAbstractItemView(parent)
63 {
64     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
65 }
66 
67 /*!
68     Returns the position of the item in viewport coordinates.
69 */
70 
itemViewportRect(const QModelIndex & index) const71 QRect LinearView::itemViewportRect(const QModelIndex &index) const
72 {
73     QRect rect = itemRect(index);
74     QRect result(rect.left() - horizontalScrollBar()->value(),
75                  rect.top() - verticalScrollBar()->value(),
76                  rect.width(), viewport()->height());
77 
78     return result;
79 }
80 
81 /*!
82     Returns the rectangle of the item at position \a index in the
83     model. The rectangle is in contents coordinates.
84 */
85 
itemRect(const QModelIndex & index) const86 QRect LinearView::itemRect(const QModelIndex &index) const
87 {
88     if (!index.isValid())
89         return QRect();
90     else
91         return QRect(index.row(), 0, 1, 1);
92 }
93 
94 
ensureVisible(const QModelIndex & index)95 void LinearView::ensureVisible(const QModelIndex &index)
96 {
97     QRect area = viewport()->rect();
98     QRect rect = itemViewportRect(index);
99 
100     if (rect.left() < area.left())
101         horizontalScrollBar()->setValue(
102             horizontalScrollBar()->value() - rect.left());
103     else if (rect.right() > area.right())
104         horizontalScrollBar()->setValue(
105             horizontalScrollBar()->value() + rect.left() - area.width());
106 }
107 
108 /*!
109     Returns the item that covers the coordinate given in the view.
110 */
111 
itemAt(int x,int) const112 QModelIndex LinearView::itemAt(int x, int /* y */) const
113 {
114     int row = x + horizontalScrollBar()->value();
115 
116     return model()->index(row, 0, QModelIndex());
117 }
118 
119 //void LinearView::dataChanged(const QModelIndex &/* topLeft */,
120 //    const QModelIndex &/* bottomRight */)
121 //{
122 //    updateGeometries();
123 //    if (isVisible())
124 //        repaint();
125 //}
126 
rowsInserted(const QModelIndex &,int,int)127 void LinearView::rowsInserted(const QModelIndex &/* parent */, int /* start */,
128     int /* end */)
129 {
130     updateGeometries();
131     if (isVisible())
132         repaint();
133 }
134 
rowsRemoved(const QModelIndex &,int,int)135 void LinearView::rowsRemoved(const QModelIndex &/* parent */, int /* start */,
136     int /* end */)
137 {
138     updateGeometries();
139     if (isVisible())
140         repaint();
141 }
142 /*
143 void LinearView::verticalScrollbarAction(int action)
144 {
145 }
146 
147 void LinearView::horizontalScrollbarAction(int action)
148 {
149 }
150 */
151 
152 /*!
153     Select the items in the model that lie within the rectangle specified by
154     \a rect, using the selection \a command.
155 */
156 
setSelection(const QRect & rect,QItemSelectionModel::SelectionFlags command)157 void LinearView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
158 {
159     QModelIndex leftIndex = itemAt(rect.left(), 0);
160     QModelIndex rightIndex = itemAt(rect.right(), 0);
161 
162     QItemSelection selection(leftIndex, rightIndex);
163 
164     selectionModel()->select(selection, command);
165 }
166 
moveCursor(QAbstractItemView::CursorAction cursorAction,Qt::KeyboardModifiers)167 QModelIndex LinearView::moveCursor(QAbstractItemView::CursorAction cursorAction,
168                                    Qt::KeyboardModifiers)
169 {
170     QModelIndex current = currentIndex();
171 
172     switch (cursorAction) {
173     case MoveLeft:{
174         if (current.row() > 0)
175             return model()->index(current.row() - 1, 0, QModelIndex());
176         else
177             return model()->index(0, 0, QModelIndex());
178         break;}
179     case MoveRight:{
180         if (current.row() < rows(current) - 1)
181             return model()->index(current.row() + 1, 0, QModelIndex());
182         else
183             return model()->index(rows(current) - 1, 0,QModelIndex());
184         break;}
185     case MoveUp:
186         return current;
187     case MoveDown:
188         return current;
189     case MovePageUp:
190         return current;
191     case MovePageDown:
192         return current;
193     case MoveHome:
194         return model()->index(0, 0, QModelIndex());
195     case MoveEnd:
196         return model()->index(rows(current) - 1, 0, QModelIndex());
197     default:
198         return current;
199     }
200 }
201 
horizontalOffset() const202 int LinearView::horizontalOffset() const
203 {
204     return horizontalScrollBar()->value();
205 }
206 
verticalOffset() const207 int LinearView::verticalOffset() const
208 {
209     return verticalScrollBar()->value();
210 }
211 
212 /*!
213     Returns a rectangle corresponding to the selection in viewport cooridinates.
214 */
215 
selectionViewportRect(const QItemSelection & selection) const216 QRect LinearView::selectionViewportRect(const QItemSelection &selection) const
217 {
218     int ranges = selection.count();
219 
220     if (ranges == 0)
221         return QRect();
222 
223     // Note that we use the top and bottom functions of the selection range
224     // since the data is stored in rows.
225 
226     int firstRow = selection.at(0).top();
227     int lastRow = selection.at(0).top();
228 
229     for (int i = 0; i < ranges; ++i) {
230         firstRow = qMin(firstRow, selection.at(i).top());
231         lastRow = qMax(lastRow, selection.at(i).bottom());
232     }
233 
234     QModelIndex firstItem = model()->index(qMin(firstRow, lastRow), 0,
235         QModelIndex());
236     QModelIndex lastItem = model()->index(qMax(firstRow, lastRow), 0,
237         QModelIndex());
238 
239     QRect firstRect = itemViewportRect(firstItem);
240     QRect lastRect = itemViewportRect(lastItem);
241 
242     return QRect(firstRect.left(), firstRect.top(),
243         lastRect.right() - firstRect.left(), firstRect.height());
244 }
245 
paintEvent(QPaintEvent * event)246 void LinearView::paintEvent(QPaintEvent *event)
247 {
248     QPainter painter(viewport());
249 
250     QRect updateRect = event->rect();
251     QBrush background(Qt::black);
252     QPen foreground(Qt::white);
253 
254     painter.fillRect(updateRect, background);
255     painter.setPen(foreground);
256 
257     QModelIndex firstItem = itemAt(updateRect.left(), updateRect.top());
258     if (!firstItem.isValid())
259         firstItem = model()->index(0, 0, QModelIndex());
260 
261     QModelIndex lastItem = itemAt(updateRect.right(), updateRect.bottom());
262     if (!lastItem.isValid())
263         lastItem = model()->index(rows() - 1, 0, QModelIndex());
264 
265     int x = updateRect.left();
266     //int top = updateRect.top();
267     //int bottom = updateRect.bottom();
268 
269     int row = firstItem.row();
270     QModelIndex index = model()->index(row, 0, QModelIndex());
271     int value = model()->data(index, Qt::DisplayRole).toInt();
272     int midPoint = viewport()->height()/2;
273     int y2 = midPoint - int(value * midPoint/255.0);
274 
275     while (row <= lastItem.row()) {
276 
277         QModelIndex index = model()->index(row, 0, QModelIndex());
278         int value = model()->data(index, Qt::DisplayRole).toInt();
279 
280         int y1 = y2;
281         y2 = midPoint - int(value * midPoint/255.0);
282 
283         painter.drawLine(x-1, y1, x, y2);
284         ++row; ++x;
285     }
286 }
287 
resizeEvent(QResizeEvent *)288 void LinearView::resizeEvent(QResizeEvent * /* event */)
289 {
290     updateGeometries();
291 }
292 
updateGeometries()293 void LinearView::updateGeometries()
294 {
295     if (viewport()->width() < rows()) {
296         horizontalScrollBar()->setPageStep(viewport()->width());
297         horizontalScrollBar()->setRange(0, rows() - viewport()->width() - 1);
298     }
299 }
300 
sizeHint() const301 QSize LinearView::sizeHint() const
302 {
303     return QSize(rows(), 200);
304 }
305 
rows(const QModelIndex & index) const306 int LinearView::rows(const QModelIndex &index) const
307 {
308     return model()->rowCount(model()->parent(index));
309 }
310 
isIndexHidden(const QModelIndex & index) const311 bool LinearView::isIndexHidden(const QModelIndex &index) const
312 {
313     return false;
314 }
315