66fabf5ac1534817781ebe07a453bbdbc2bedaad
[pulseview.git] / pv / views / tabular_decoder / model.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2020 Soeren Apel <soeren@apelpie.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <QDebug>
21 #include <QString>
22
23 #include "pv/views/tabular_decoder/view.hpp"
24
25 using std::make_shared;
26
27 namespace pv {
28 namespace views {
29 namespace tabular_decoder {
30
31 AnnotationCollectionModel::AnnotationCollectionModel(QObject* parent) :
32         QAbstractTableModel(parent),
33         all_annotations_(nullptr),
34         prev_segment_(0),
35         prev_last_row_(0)
36 {
37         GlobalSettings::add_change_handler(this);
38         theme_is_dark_ = GlobalSettings::current_theme_is_dark();
39
40         // TBD Maybe use empty columns as indentation levels to indicate stacked decoders
41         header_data_.emplace_back(tr("Sample"));     // Column #0
42         header_data_.emplace_back(tr("Time"));       // Column #1
43         header_data_.emplace_back(tr("Decoder"));    // Column #2
44         header_data_.emplace_back(tr("Ann Row"));    // Column #3
45         header_data_.emplace_back(tr("Ann Class"));  // Column #4
46         header_data_.emplace_back(tr("Value"));      // Column #5
47 }
48
49 QVariant AnnotationCollectionModel::data(const QModelIndex& index, int role) const
50 {
51         if (!index.isValid())
52                 return QVariant();
53
54         const Annotation* ann =
55                 static_cast<const Annotation*>(index.internalPointer());
56
57         if (role == Qt::DisplayRole) {
58                 switch (index.column()) {
59                 case 0: return QVariant((qulonglong)ann->start_sample());  // Column #0, Start Sample
60                 case 1: return QVariant(0/*(qulonglong)ann->start_sample()*/);  // Column #1, Start Time
61                 case 2: return QVariant(ann->row()->decoder()->name());    // Column #2, Decoder
62                 case 3: return QVariant(ann->row()->description());        // Column #3, Ann Row
63                 case 4: return QVariant(ann->ann_class_description());     // Column #4, Ann Class
64                 case 5: return QVariant(ann->longest_annotation());        // Column #5, Value
65                 default: return QVariant();
66                 }
67         }
68
69         if (role == Qt::BackgroundRole) {
70                 if (theme_is_dark_)
71                         return QBrush(ann->dark_color());
72                 else
73                         return QBrush(ann->bright_color());
74         }
75
76         return QVariant();
77 }
78
79 Qt::ItemFlags AnnotationCollectionModel::flags(const QModelIndex& index) const
80 {
81         if (!index.isValid())
82                 return 0;
83
84         return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
85 }
86
87 QVariant AnnotationCollectionModel::headerData(int section, Qt::Orientation orientation,
88         int role) const
89 {
90         if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
91                 return header_data_.at(section);
92
93         return QVariant();
94 }
95
96 QModelIndex AnnotationCollectionModel::index(int row, int column,
97         const QModelIndex& parent_idx) const
98 {
99         (void)parent_idx;
100
101         if (!all_annotations_)
102                 return QModelIndex();
103
104         if ((size_t)row > all_annotations_->size())
105                 return QModelIndex();
106
107         return createIndex(row, column, (void*)(all_annotations_->at(row)));
108 }
109
110 QModelIndex AnnotationCollectionModel::parent(const QModelIndex& index) const
111 {
112         (void)index;
113
114         return QModelIndex();
115 }
116
117 int AnnotationCollectionModel::rowCount(const QModelIndex& parent_idx) const
118 {
119         (void)parent_idx;
120
121         if (!all_annotations_)
122                 return 0;
123
124         return all_annotations_->size();
125 }
126
127 int AnnotationCollectionModel::columnCount(const QModelIndex& parent_idx) const
128 {
129         (void)parent_idx;
130
131         return header_data_.size();
132 }
133
134 void AnnotationCollectionModel::set_signal_and_segment(data::DecodeSignal* signal, uint32_t current_segment)
135 {
136         if (!signal) {
137                 all_annotations_ = nullptr;
138                 dataChanged(QModelIndex(), QModelIndex());
139                 layoutChanged();
140                 return;
141         }
142
143         all_annotations_ = signal->get_all_annotations_by_segment(current_segment);
144
145         if (!all_annotations_ || all_annotations_->empty()) {
146                 prev_segment_ = current_segment;
147                 return;
148         }
149
150         const size_t new_row_count = all_annotations_->size() - 1;
151
152         // Force the view associated with this model to update when the segment changes
153         if (prev_segment_ != current_segment) {
154                 dataChanged(QModelIndex(), QModelIndex());
155                 layoutChanged();
156         } else {
157                 // Force the view associated with this model to update when we have more annotations
158                 if (prev_last_row_ < new_row_count) {
159                         dataChanged(index(prev_last_row_, 0, QModelIndex()),
160                                 index(new_row_count, 0, QModelIndex()));
161                         layoutChanged();
162                 }
163         }
164
165         prev_segment_ = current_segment;
166         prev_last_row_ = new_row_count;
167 }
168
169 void AnnotationCollectionModel::on_setting_changed(const QString &key, const QVariant &value)
170 {
171         (void)key;
172         (void)value;
173
174         // We don't really care about the actual setting, we just update the
175         // flag that indicates whether we are using a bright or dark color theme
176         theme_is_dark_ = GlobalSettings::current_theme_is_dark();
177 }
178
179 } // namespace tabular_decoder
180 } // namespace views
181 } // namespace pv